#c# #wpf #binding
#c# #wpf #привязка
Вопрос:
Как я могу привязать поля класса к элементам внутри пользовательского шаблона ListBoxItem?? В этом примере кода отсутствуют некоторые аспекты, такие как определение класса, имя ListBox и т.д., Я просто испытываю трудности с процессом привязки.
<ListBox>
<ListBox.Resources>
<Style TargetType="ListBoxItem">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<!-- how to bind class fields to these elements -->
<StackPanel Orientation="Horizontal">
<Label></Label>
<Image></Image>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.Resources>
<!-- adding items dynamically -->
</ListBox>
Код C # должен выглядеть следующим образом:
ListBoxItem listBoxItem = new ListBoxItem();
listBoxItem.Content = new MyClass(){ Name="MyName", Image="ImagePath"}
... append to ListBox ...
Ответ №1:
При разработке в WPF поощряется MvvM для содействия разделению проблем. Для этого нужно было бы реализовать модель представления со свойствами, которые затем были бы привязаны к представлению. Когда вы хотите, чтобы пользовательский интерфейс (view) был в курсе изменений в данных, которые предоставляет View Model, нужно реализовать INotifyPropertyChanged
интерфейс, например:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using System.Windows.Threading;
namespace ViewModels
{
public class BaseViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public BaseViewModel()
{
//ctor
}
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
UIThread( () =>
{
//make sure the event is raised on the main thread
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
});
}
Dispatcher _dispacther;
protected void UIThread(Action action)
{
if (_dispacther == null)
{
_dispacther = Dispatcher.CurrentDispatcher;
}
_dispacther.Invoke(action);
}
}
}
Ваш Hello
класс был бы производным от BaseViewModel и предоставлял бы OnPropertyChanged(); в свойстве, подобном этому:
private string name;
public string Name
{
get { return name; }
set { name= value; OnPropertyChanged(); }
}
Теперь, когда вы меняете имя выбранного элемента в списке, это будет отражено в пользовательском интерфейсе. Попробуйте!
Эта реализация гарантирует, что событие вызывается в основном потоке, поэтому вам не нужно делать это при вызове события. Также [CallerMemberName]
будет заполнено имя свойства, которое вы вызываете!
Ответ №2:
Разобрался. Класс C #:
public class Hello
{
public string Name { get; set; }
public string Description { get; set; }
public string ImagePath { get; set; }
}
Динамическое добавление C #:
ListBoxItem lbi = new ListBoxItem();
lbi.Content = new Hello() { Name = "hello man", Description="I am superman.", ImagePath="Images/myimage.png"};
menu.Items.Add(lbi);
XAML:
<ListBox Name="menu" ItemsSource="{Binding}">
<ListBox.Resources>
<Style TargetType="ListBoxItem">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Label FontWeight="Bold" Content="{Binding Name}"></Label>
<Label Content="{Binding Description}"></Label>
<Image Source="{Binding ImagePath}" Width="30" Height="30"></Image>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.Resources>
</ListBox>
Комментарии:
1. Помните о том, что
INotfyPropertyChanged
интерфейс ДОЛЖЕН БЫТЬ РЕАЛИЗОВАН, иначе ваши изменения не будут отражены на экране! Для привязки поддерживаются только свойства.2. Объявите изменения, на которые вы ссылаетесь.