0

WPF では、2 列の ListView があり、最初の列はボタンである必要があります。私が間違っている場合は修正してください。ただし、ListView にボタンを実装する唯一の方法は、DataTemplate を使用することです。これで私が見つけた問題は、元のボタンのプロパティが DataTemplate にマップされている場合、元のボタンのプロパティを維持する方法がないため、バインディングを使用して個々のプロパティ (実際にはカスタム ユーザー コントロールを使用しているため、カスタム プロパティを含む) を再マップする必要があることです。これは Button から継承します)。これは、すべてのプロパティを手動でマップする必要があるのは無関係に思えるので、これらのプロパティを自動的に永続化するためのより良い方法があるでしょうか?

ここに私のテストコードがあります:

public MainWindow() {
    InitializeComponent();

    ObservableCollection<ScreenRequest> screenRequests = new ObservableCollection<ScreenRequest>() {
        new ScreenRequest("A", "1"),
        new ScreenRequest("B", "2")
    };
    myListView.ItemsSource = screenRequests;
}   

public class ScreenRequest {
    public CustomButton ScreenButton { set; get; }
    public string Details { set; get; }

    public ScreenRequest(string buttonText, string customProperty) {
        this.ScreenButton = new CustomButton();
        this.ScreenButton.Content = buttonText;
        this.ScreenButton.CustomProperty = customProperty;
        this.ScreenButton.Click += new RoutedEventHandler(InitiateScreenRequest);
    }

    private void InitiateScreenRequest(object sender, RoutedEventArgs e) {
        CustomButton screenBtn = (CustomButton)sender;
        screenBtn.Content = "BUTTON TEXT CHANGED";
    }
}   

public class CustomButton : Button  {
    public string CustomProperty { get; set; }
}

そしてXAML:

<Window...
...
    <Window.Resources>
        <DataTemplate x:Key="ButtonTemplate">
            <local:CustomButton Content="{Binding ScreenButton.Content}"/>
        </DataTemplate>
    </Window.Resources>
    <Grid x:Name="grdMain">
    ...
        <ListView...
            <ListView.View>
                <GridView x:Name="gridView">
                    <GridViewColumn CellTemplate="{StaticResource ButtonTemplate}" Width="Auto" Header="Screen" HeaderStringFormat="Screen"/>
                    <GridViewColumn Header="Details" HeaderStringFormat="Details" DisplayMemberBinding="{Binding Details}"/>
                </GridView>
            </ListView.View>
        </ListView>
    </Grid>
</Window>

だから私の質問は:

  1. CustomButton のすべてのプロパティを DataTemplate に引き継ぐために手動でマップする必要がありますか?それとも、プロパティを自動的に永続化するためのキャッチオールですか?
  2. ボタンにくっつくようにバインディングで CustomProperty プロパティをマップするにはどうすればよいですか? これには DependencyProperty を使用しますか?
  3. GridView のボタンをクリックすると InitiateScreenRequest 関数が呼び出されるように、クリック イベントを維持するにはどうすればよいですか? 理想的には、すべてのボタンに対して 1 つのメソッドを宣言したいと考えていますが、まだその段階に達していません。

リストビューのボタンに関するヘルプや洞察をいただければ幸いです。

4

1 に答える 1

2
<Window x:Class="MiscSamples.TonyRush"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="TonyRush" Height="300" Width="300">
    <ListView ItemsSource="{Binding}">
        <ListView.View>
            <GridView>
                <GridViewColumn Width="Auto" Header="Screen" HeaderStringFormat="Screen">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <Button Command="{Binding SomeAction}" Content="{Binding ActionDescription}" Width="100"/>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
                <GridViewColumn Header="Details" HeaderStringFormat="Details" DisplayMemberBinding="{Binding Details}" Width="100"/>
            </GridView>
        </ListView.View>
    </ListView>
</Window>

コードビハインド:

 public partial class TonyRush : Window
    {
        public TonyRush()
        {
            InitializeComponent();
            DataContext = new List<ScreenRequest>
                              {
                                  new ScreenRequest() {ActionDescription = "Click Me!"},
                                  new ScreenRequest() {ActionDescription = "Click Me Too!"},
                                  new ScreenRequest() {ActionDescription = "Click Me Again!!"},
                              };
        }
    }

ビューモデル:

public class ScreenRequest: INotifyPropertyChanged
    {
        public Command SomeAction { get; set; }

        private string _actionDescription;
        public string ActionDescription
        {
            get { return _actionDescription; }
            set
            {
                _actionDescription = value;
                NotifyPropertyChanged("ActionDescription");
            }
        }

        private string _details;
        public string Details
        {
            get { return _details; }
            set
            {
                _details = value;
                NotifyPropertyChanged("Details");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        public ScreenRequest()
        {
            SomeAction = new Command(ExecuteSomeAction) {IsEnabled = true};
        }

        //public SomeProperty YourProperty { get; set; }

        private void ExecuteSomeAction()
        {
            //Place your custom logic here based on YourProperty
            ActionDescription = "Clicked!!";
            Details = "Some Details";
        }
    }

重要な部分:Commandクラス:

//Dead-simple implementation of ICommand
    //Serves as an abstraction of Actions performed by the user via interaction with the UI (for instance, Button Click)
    public class Command : ICommand
    {
        public Action Action { get; set; }

        public void Execute(object parameter)
        {
            if (Action != null)
                Action();
        }

        public bool CanExecute(object parameter)
        {
            return IsEnabled;
        }

        private bool _isEnabled;
        public bool IsEnabled
        {
            get { return _isEnabled; }
            set
            {
                _isEnabled = value;
                if (CanExecuteChanged != null)
                    CanExecuteChanged(this, EventArgs.Empty);
            }
        }

        public event EventHandler CanExecuteChanged;

        public Command(Action action)
        {
            Action = action;
        }
    }

結果:

ここに画像の説明を入力

ノート:

UI がデータや機能からどのように分離されているかを見てみましょう。これがWPFのやり方です。UI とデータ / ビジネス コードを混在させないでください。

ViewModelのCommandは、 の抽象化として機能しますButton。ViewModel は aButtonが何であるかを知りませんし、そうすべきでもありません。詳細が必要な場合はお知らせください。

于 2013-03-28T21:26:11.863 に答える