2

WPFのリストボックスには、次のテンプレートがあります。

<ControlTemplate x:Key="ListBoxItemControlTemplate1" TargetType="{x:Type ListBoxItem}">
    <StackPanel Orientation="Horizontal" Background="Silver">
        <CheckBox Content="CheckBox" VerticalAlignment="Center"/>
        <Label Content="Label" Padding="5,0" Width="260" VerticalAlignment="Center" Background="#F3D6D6D6" Margin="5,0"/>
        <Button Content="Edit" Width="Auto" Padding="1" Margin="2.5,0" HorizontalAlignment="Right" Click="Button_Click"/>
    </StackPanel>
</ControlTemplate>

また、listBoxItemの対応するボタンを押すたびに、できれば名前を使用せずに、同じlistBoxItemのラベルを変更したいと思います。
StackPanelだと思っていた「このボタンの親のラベルを使う」という言い方があるのではないかと思っていたのですが、インターネット上で役に立つものが見つかりませんでした。

4

3 に答える 3

2

より良い解決策は、DataTemplate でビュー モデルを使用することだと思います。コードを設定したら、エラーの可能性はほとんどなく、何度も再利用できます。

ビューモデルは次のようになります

public class ViewModel : INotifyPropertyChanged
{
    private ObservableCollection<ItemViewModel> _items;

    public ViewModel()
    {
        _items = new ObservableCollection<ItemViewModel>(new List<ItemViewModel>()
            {
                new ItemViewModel() { Label = "Item1", IsChecked = false },
                new ItemViewModel() { Label = "Item2", IsChecked = true },
                new ItemViewModel() { Label = "Item3", IsChecked = true },
                new ItemViewModel() { Label = "Item4", IsChecked = false },
                new ItemViewModel() { Label = "Item5", IsChecked = false },
            });

    }

    public ObservableCollection<ItemViewModel> Items
    {
        get
        {

            return this._items;
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    // Create the OnPropertyChanged method to raise the event
    protected void OnPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }
}

public class ItemViewModel  : INotifyPropertyChanged
{
    private bool _isChecked = false;
    private string _label = "Label";

    public ICommand ButtonCommand { get; private set; }

    public ItemViewModel()
    {
        this.ButtonCommand = new DelegateCommand(Com_ButtonCommand);
    }

    public void Com_ButtonCommand(object parameter)
    {
        this.Label = "New Label text";
    }

    public string Label
    {
        get
        {
            return this._label;
        }
        set
        {
            this._label = value;
            this.OnPropertyChanged("Label");
        }
    }

    public bool IsChecked
    {
        get
        {
            return this._isChecked;
        }
        set
        {
            this._isChecked = value;
            this.OnPropertyChanged("IsChecked");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    // Create the OnPropertyChanged method to raise the event
    protected void OnPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }
}
public class DelegateCommand : ICommand
{
    private readonly Predicate<object> _canExecute;
    private readonly Action<object> _execute;

    public event EventHandler CanExecuteChanged;

    public DelegateCommand(Action<object> execute)
        : this(execute, null)
    {
    }

    public DelegateCommand(Action<object> execute,
                   Predicate<object> canExecute)
    {
        _execute = execute;
        _canExecute = canExecute;
    }

    public bool CanExecute(object parameter)
    {
        if (_canExecute == null)
        {
            return true;
        }

        return _canExecute(parameter);
    }

    public void Execute(object parameter)
    {
        _execute(parameter);
    }

    public void RaiseCanExecuteChanged()
    {
        if (CanExecuteChanged != null)
        {
            CanExecuteChanged(this, EventArgs.Empty);
        }
    }
}

ここには 3 つのクラスがあり、そのうちの 1 つはヘルパーです。

ViewModel --> メインの ViewModel、ItemViewModel --> 各アイテムのモデル、DelegateCommand --> ボタンをビュー モデルにマップできます

xamlは次のようになります

<ListBox ItemsSource="{Binding Items}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal" Background="Silver">
                        <CheckBox IsChecked="{Binding IsChecked}" Content="CheckBox" VerticalAlignment="Center"/>
                        <Label Content="{Binding Label}" Padding="5,0" Width="260" VerticalAlignment="Center" Background="#F3D6D6D6" Margin="5,0"/>
                        <Button Command="{Binding ButtonCommand}" />
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

「{Binding}」キーワードに注意してください。これは、各データ テンプレートを独自のビュー モデル (この場合は IsChecked および Label) のその名前を持つメンバーに「バインド」します。

ViewModel をロードするには、ユーザー コントロールのコード ビハインドに次の行を追加します (MVVM を使用すると、ユーザー コントロールのコード ビハインドに触れることはほとんどありません)。

this.DataContext = new ViewModel();

ビューモデルを初めて見るときは、大変な作業のように思えるかもしれませんが、ほとんどが再利用可能であり、このようなことを行うためのデファクト スタンダード (MVVM) です。開始するために必要なすべてのコードが含まれています。

次のクラスと DelegateCommand は、後で使用するために保持する必要があります。上記のスニペットには既に含まれています。

    public class ViewModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        // Create the OnPropertyChanged method to raise the event
        protected void OnPropertyChanged(string name)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name));
            }
        }
    }
于 2012-06-25T14:23:03.443 に答える
1

背面でビューモデルを使用することをお勧めします。その VM は、ボタンにバインドされたコマンドを公開します。さらに、ラベルの名前を含む DependencyProperty を公開します。そして、ラベルはそのプロパティにバインドされています。ボタンを押すと、コマンドが実行され、ラベルのテキストが変更され、データバインディングを介してラベルの新しいテキストが更新されます。

もう 1 つのオプションは、お勧めしませんが、FindName を使用してラベルを見つけることです。または、VisualTreeHelper を使用してコントロールを反復処理することは、本当に悪い (しかし機能する) ことです。

于 2012-06-25T14:04:52.197 に答える
1

VisualTreeをナビゲートして parent を見つけStackPanel、それを検索して更新StackPanelする子を見つけます。Label

興味があれば、これを簡単にするVisualTreeHelpersをブログに投稿しています。

var parent = VisualTreeHelpers.FindAncestor<StackPanel>((Button)sender);
if (parent == null) return;

var lbl = VisualTreeHelpers.FindChild<Label>(parent);
if (lbl == null) return;

lbl.Content = "Some Text";

これは、MVVM デザイン パターンを使用していないことを示しています。Label.ContentMVVM を使用していた場合、プロパティをに格納しViewModelButtonコマンドは の を指しCommandViewModelDataBound アイテムを として渡す必要があるCommandParameterため、どのラベルを更新するかがわかります。

<ControlTemplate x:Key="ListBoxItemControlTemplate1" TargetType="{x:Type ListBoxItem}">
    <StackPanel Orientation="Horizontal" Background="Silver">
        <CheckBox Content="CheckBox" VerticalAlignment="Center"/>
        <Label Content="{Binding SomeText}" ... />
        <Button Content="Edit" 
                Command="{Binding ElementName=MyListBox, Path=DataContext.EditCommand}"
                CommandParameter="{Binding }" />
    </StackPanel>
</ControlTemplate>
于 2012-06-25T14:06:47.610 に答える