programing

커스텀 리스트에 WPF ComboBox 바인딩

subpage 2023. 4. 9. 21:30
반응형

커스텀 리스트에 WPF ComboBox 바인딩

Selected Item/Selected Value가 업데이트되지 않은 ComboBox가 있습니다.

Items ComboBox .RAS CollectionView 뷰 뷰 뷰 뷰 뷰 뷰 뷰 뷰 뷰 뷰 뷰 뷰 모델 두 (SelectedItem ★★★★★★★★★★★★★★★★★」SelectedValueView Model 른 、 른 view view view view view 。바인딩에 에 MessageBox를 했는데, "MessageBox"는 "MessageBox"입니다.SelectedItem/SelectedValue이치노

View Model 클래스는 다음과 같습니다.

public ConnectionViewModel
{
    private readonly CollectionView _phonebookEntries;
    private string _phonebookeEntry;

    public CollectionView PhonebookEntries
    {
        get { return _phonebookEntries; }
    }

    public string PhonebookEntry
    {
        get { return _phonebookEntry; }
        set
        {
            if (_phonebookEntry == value) return;
            _phonebookEntry = value;
            OnPropertyChanged("PhonebookEntry");
        }
    }
}

_phonebookEntries 컬렉션은 컨스트럭터에서 비즈니스 객체에서 초기화 중입니다.ComboBox XAML은 다음과 같습니다.

<ComboBox ItemsSource="{Binding Path=PhonebookEntries}"
    DisplayMemberPath="Name"
    SelectedValuePath="Name"
    SelectedValue="{Binding Path=PhonebookEntry}" />

되는 실제 때 RAS에 값이기 때문에 ComboBox는 ComboBox에 표시됩니다.VPN 접속을 확립할 때 RAS에 전달해야 하는 값이기 때문입니다.DisplayMemberPath ★★★★★★★★★★★★★★★★★」SelectedValuePathconnect 、 ConnectionViewModel 、이름 、이름 。 는 ★★★★★★★★★★★★★★★★★★★★★★」DataTemplateItemsControlData Context View Model data data data 。

ComboBox에는 아이템 리스트가 올바르게 표시되어 UI에서 문제없이 선택할 수 있습니다.단, 명령어 메시지박스를 표시하면 전화번호부는항목 속성에 ComboBox에서 선택한 값이 아닌 초기 값이 여전히 있습니다.다른 TextBox 인스턴스는 정상적으로 업데이트되고 MessageBox에 표시됩니다.

ComboBox의 데이터 바인딩에서 부족한 점은 무엇입니까?여러 번 찾아봤지만 내가 잘못하고 있는 건 아무것도 못 찾은 것 같아.


이것은 제가 보고 있는 행동입니다만, 제 특정의 문맥에서는 어떠한 이유로도 효과가 없습니다.

Window 윈도 뷰 모델입니다.CollectionViewConnection View Models 。MainWindowView.xaml DataContext MainWindowViewModel main main 。 WindowView에는 Main WindowView.xaml이 .ItemsControlConnection View Models (접속 뷰 모델)DataTemplate를 사용합니다.는 TextBox ConnectionViewModel을 .Text="{Binding Path=ConnectionName}".

public class ConnectionViewModel : ViewModelBase
{
    public string Name { get; set; }
    public string Password { get; set; }
}

public class MainWindowViewModel : ViewModelBase
{
    // List<ConnectionViewModel>...
    public CollectionView Connections { get; set; }
}

XAML 코드 배후에 있는 것

public partial class Window1
{
    public Window1()
    {
        InitializeComponent();
        DataContext = new MainWindowViewModel();
    }
}

그러면 XAML:

<DataTemplate x:Key="listTemplate">
    <Grid>
        <ComboBox ItemsSource="{Binding Path=PhonebookEntries}"
            DisplayMemberPath="Name"
            SelectedValuePath="Name"
            SelectedValue="{Binding Path=PhonebookEntry}" />
        <TextBox Text="{Binding Path=Password}" />
    </Grid>
</DataTemplate>

<ItemsControl ItemsSource="{Binding Path=Connections}"
    ItemTemplate="{StaticResource listTemplate}" />

텍스트 상자는 모두 올바르게 바인딩되며 데이터는 텍스트 상자와 View Model 간에 문제 없이 이동합니다.Combo Box만 작동하지 않습니다.

전화번호부에 대한 당신의 추정은 옳습니다.엔트리 클래스

하고 있는 계층을의 각 에 대해 ItemsControl내가 보기엔 좀 바보같다.


위의 예에 따라 문제를 나타내는 테스트 구현을 다음에 나타냅니다.

XAML:

<Window x:Class="WpfApplication7.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <Window.Resources>
        <DataTemplate x:Key="itemTemplate">
            <StackPanel Orientation="Horizontal">
                <TextBox Text="{Binding Path=Name}" Width="50" />
                <ComboBox ItemsSource="{Binding Path=PhonebookEntries}"
                    DisplayMemberPath="Name"
                    SelectedValuePath="Name"
                    SelectedValue="{Binding Path=PhonebookEntry}"
                    Width="200"/>
            </StackPanel>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <ItemsControl ItemsSource="{Binding Path=Connections}"
            ItemTemplate="{StaticResource itemTemplate}" />
    </Grid>
</Window>

코드 이면:

namespace WpfApplication7
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
            DataContext = new MainWindowViewModel();
        }
    }

    public class PhoneBookEntry
    {
        public string Name { get; set; }
        public PhoneBookEntry(string name)
        {
            Name = name;
        }
    }

    public class ConnectionViewModel : INotifyPropertyChanged
    {

        private string _name;

        public ConnectionViewModel(string name)
        {
            _name = name;
            IList<PhoneBookEntry> list = new List<PhoneBookEntry>
                                             {
                                                 new PhoneBookEntry("test"),
                                                 new PhoneBookEntry("test2")
                                             };
            _phonebookEntries = new CollectionView(list);
        }
        private readonly CollectionView _phonebookEntries;
        private string _phonebookEntry;

        public CollectionView PhonebookEntries
        {
            get { return _phonebookEntries; }
        }

        public string PhonebookEntry
        {
            get { return _phonebookEntry; }
            set
            {
                if (_phonebookEntry == value) return;
                _phonebookEntry = value;
                OnPropertyChanged("PhonebookEntry");
            }
        }

        public string Name
        {
            get { return _name; }
            set
            {
                if (_name == value) return;
                _name = value;
                OnPropertyChanged("Name");
            }
        }
        private void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
        public event PropertyChangedEventHandler PropertyChanged;
    }

    public class MainWindowViewModel
    {
        private readonly CollectionView _connections;

        public MainWindowViewModel()
        {
            IList<ConnectionViewModel> connections = new List<ConnectionViewModel>
                                                          {
                                                              new ConnectionViewModel("First"),
                                                              new ConnectionViewModel("Second"),
                                                              new ConnectionViewModel("Third")
                                                          };
            _connections = new CollectionView(connections);
        }

        public CollectionView Connections
        {
            get { return _connections; }
        }
    }
}

그 예를 실행하면 내가 말하는 행동을 알 수 있을 것이다.TextBox는 편집할 때 바인딩이 올바르게 업데이트되지만 ComboBox는 업데이트되지 않습니다.부모 View Model을 소개한 것은 매우 혼란스러운 일입니다.

저는 현재 DataContext의 자녀에게 바인드된 아이템에 해당 자녀가 DataContext로 있다고 생각하고 작업하고 있습니다.어떻게 해서든 이 문제를 해결할 수 있는 문서를 찾을 수 없습니다.

예.,

>= Main Window Model - -> Data Context = Main Window View Model
에 바인드...항목 -> 데이터 컨텍스트 -> 데이터 컨텍스트 엔트리
-> Data = 전화번호부'데이터 콘텍스트='엔트리관련지어져 있음)★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

그것이 내 추측을 더 잘 설명해 줄 수 있을지 모르겠다.


내 가정을 확인하기 위해 TextBox의 바인딩을 다음과 같이 변경합니다.

<TextBox Text="{Binding Mode=OneWay}" Width="50" />

또한 TextBox 바인딩 루트(DataContext와 비교 중)가 ConnectionViewModel 인스턴스임을 나타냅니다.

DisplayMemberPath 및 SelectedValuePath를 "Name"으로 설정했기 때문에 공용 속성 이름을 가진 클래스 PhoneBookEntry가 있을 것으로 예상됩니다.

Data Context를 Connection View Model 개체로 설정했습니까?

당신의 코드를 복사하고 약간의 수정을 가했는데, 정상적으로 동작하고 있는 것 같습니다.뷰모델 PhoneBookEntry 속성과 콤보박스의 선택된 아이템을 변경할 수 있으며 콤보박스에서 선택한 아이템을 변경할 수 있으며 뷰모델 PhoneBookEntry 속성이 올바르게 설정되어 있습니다.

XAML 콘텐츠는 다음과 같습니다.

<Window x:Class="WpfApplication6.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="300" Width="300">
<Grid>
    <StackPanel>
        <Button Click="Button_Click">asdf</Button>
        <ComboBox ItemsSource="{Binding Path=PhonebookEntries}"
                  DisplayMemberPath="Name"
                  SelectedValuePath="Name"
                  SelectedValue="{Binding Path=PhonebookEntry}" />
    </StackPanel>
</Grid>
</Window>

내 암호는 다음과 같습니다.

namespace WpfApplication6
{

    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
            ConnectionViewModel vm = new ConnectionViewModel();
            DataContext = vm;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            ((ConnectionViewModel)DataContext).PhonebookEntry = "test";
        }
    }

    public class PhoneBookEntry
    {
        public string Name { get; set; }

        public PhoneBookEntry(string name)
        {
            Name = name;
        }

        public override string ToString()
        {
            return Name;
        }
    }

    public class ConnectionViewModel : INotifyPropertyChanged
    {
        public ConnectionViewModel()
        {
            IList<PhoneBookEntry> list = new List<PhoneBookEntry>();
            list.Add(new PhoneBookEntry("test"));
            list.Add(new PhoneBookEntry("test2"));
            _phonebookEntries = new CollectionView(list);
        }

        private readonly CollectionView _phonebookEntries;
        private string _phonebookEntry;

        public CollectionView PhonebookEntries
        {
            get { return _phonebookEntries; }
        }

        public string PhonebookEntry
        {
            get { return _phonebookEntry; }
            set
            {
                if (_phonebookEntry == value) return;
                _phonebookEntry = value;
                OnPropertyChanged("PhonebookEntry");
            }
        }

        private void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
        public event PropertyChangedEventHandler PropertyChanged;
    }
}

편집: Geoffs의 두 번째 예는 효과가 없는 것 같습니다만, 조금 이상합니다.ConnectionViewModel의 PhonebookEntries 속성을 ReadOnlyCollection 유형으로 변경하면 콤보박스의 SelectedValue 속성의 TwoWay 바인딩이 정상적으로 동작합니다.

Collection View에 문제가 있을 수 있습니다.출력 콘솔에 경고가 표시되었습니다.

System.Windows.데이터 경고: 50 : Collection View를 직접 사용하는 것은 완전히 지원되지 않습니다.기본 기능은 일부 비효율적이지만 작동하지만 고급 기능에서는 알려진 버그가 발생할 수 있습니다.이러한 문제를 방지하려면 파생 클래스를 사용하는 것을 고려해 보십시오.

편집2(.NET 4.5):DropDownList의 내용은 DisplayMemberPath가 아닌 ToString()을 기반으로 할 수 있습니다.한편 DisplayMemberPath는 선택한 항목과 표시된 항목의 멤버만 지정합니다.

데이터를 ComboBox에 바인딩하려면

List<ComboData> ListData = new List<ComboData>();
ListData.Add(new ComboData { Id = "1", Value = "One" });
ListData.Add(new ComboData { Id = "2", Value = "Two" });
ListData.Add(new ComboData { Id = "3", Value = "Three" });
ListData.Add(new ComboData { Id = "4", Value = "Four" });
ListData.Add(new ComboData { Id = "5", Value = "Five" });

cbotest.ItemsSource = ListData;
cbotest.DisplayMemberPath = "Value";
cbotest.SelectedValuePath = "Id";

cbotest.SelectedValue = "2";

ComboData외관:

public class ComboData
{ 
  public int Id { get; set; } 
  public string Value { get; set; } 
}

(주의:Id그리고.Value클래스 필드가 아닌 속성이어야 합니다.)

처음에는 같은 문제인 것처럼 보였지만, 알고 보니 NHibernate/WPF 호환성 문제였습니다.이 문제는 WPF가 객체의 동일성을 체크하는 방법에 의해 발생하였습니다.SelectedValue 속성 및 SelectedValuePath 속성에서 개체 ID 속성을 사용하여 작업을 수행할 수 있었습니다.

<ComboBox Name="CategoryList"
          DisplayMemberPath="CategoryName"
          SelectedItem="{Binding Path=CategoryParent}"
          SelectedValue="{Binding Path=CategoryParent.ID}"
          SelectedValuePath="ID">

Chester의 블로그 투고, WPF Combo Box - Selected를 참조하십시오.항목, SelectedValue 및 SelectedValuePath(NHibernate 포함)를 참조하십시오.

비슷한 문제가 있었는데 Selected는항목이 업데이트되지 않았습니다.

문제는 선택한 아이템이 리스트에 포함된 아이템과 동일한 인스턴스가 아니라는 것입니다.MyCustomObject에서 Equals() 메서드를 덮어쓰고 두 인스턴스의 ID를 비교하여 ComboBox에 동일한 오브젝트임을 알려야 했습니다.

public override bool Equals(object obj)
{
    return this.Id == (obj as MyCustomObject).Id;
}

언급URL : https://stackoverflow.com/questions/561166/binding-a-wpf-combobox-to-a-custom-list

반응형