简体   繁体   中英

Binding of changing click event

Good day. I'll try to make it shorter as possible. My XAML:

<StackPanel Grid.Row="1" Grid.Column="0" x:Name="stackActions">
            <Button x:Name="btnAction_1" Margin="5" Content="Start work" Click="btnAction_1_Click"/>
            <Button x:Name="btnAction_2" Margin="5" Content="" Visibility="Collapsed"/>
            <Button x:Name="btnAction_3" Margin="5" Content="" Visibility="Collapsed"/>
            <Button x:Name="btnAction_4" Margin="5" Content="" Visibility="Collapsed"/>
            <Button x:Name="btnAction_5" Margin="5" Content="" Visibility="Collapsed"/>
</StackPanel>

My C#:

public partial class MainWindow : Window
{
    // Method for collapsing all buttons
    public void HideAllButtons()
    {
        stackActions.Children.OfType<Button>().ToList().ForEach(button => button.Visibility = Visibility.Collapsed);
    }
    public MainWindow()
    {
        InitializeComponent();           
    }
    private void btnAction_1_Click(object sender, RoutedEventArgs e)
    {
        HideAllButtons();
        btnAction_2.Visibility = Visibility.Visible;
        btnAction_3.Visibility = Visibility.Visible;
        btnAction_2.Content = "Surveys";
        btnAction_3.Content = "ClearAll";
        btnAction_2.Click += SeeSurveys;
        btnAction_3.Click += ClearAll;           
    }
    private void SeeSurveys(object sender, RoutedEventArgs e )
    {
        btnAction_2.Click -= SeeSurveys;
        btnAction_3.Click -= ClearAll;
        btnAction_2.Content = "Draft";
        btnAction_3.Content = "OnHire";
        btnAction_4.Visibility = Visibility.Visible;
        btnAction_4.Content = "Condition";
        btnAction_5.Visibility = Visibility.Visible;
        btnAction_5.Content = "Back";
        btnAction_5.Click += btnAction_1_Click;
    }
    private void ClearAll (object sender, RoutedEventArgs e)
    {
        HideAllButtons();
        btnAction_1.Visibility = Visibility.Visible;
    }
}

Actually this is works as i want, but looking like mess with much Click += and Click -= events. I understand that making more massive code confused myseld very soon. I suppose there are any options to bind click event for each button in XAML and change the event itself in C# or reduce the quantity of Visibility checks.

The main idea is changing click events and rewriting buttons content depending of what button was clicked.

So any advice is welcome to make this code more clear and short.

Like many wpf developers and the vast majority of commercial wpf teams, I use MVVM.

With that I would be thinking in terms of templating buttons out from viewmodels that had commands.

Rather than having many buttons where I switched the event handler round, I'd have lists of commands. These could be in a model which was a hierarchical form and a layer translated or picked from that if it suited your real world requirement best.
Or A series of objects something like:

public class CommandListViewModel
{
    public int Id { get; set; }
    public ObservableCollection<CommandViewModel> Commands { get; set; }
}

public class CommandViewModel
{
    public string Name { get; set; }
    public DelegateCommand<MainWindowViewModel> Command { get; set; }
}

These are just sketched out to give an idea of what I have in mind. You would have inotifypropertychanged implemented in these viewmodels and probably want to raise change notification from the property setters.

But the idea is each level is represented by a class commandlistviewmodel which has an id and a bunch of commands with the "name". The name is displayed in a button which has that command.

Each command gets a reference to mainwindowviewmodel passed into it. So it can access properties on that. One of which would be a list or instance of commandlistviewmodel.

Hence any given command could go find a list of commands it needs to "substitute" or some other property in mainwindowviewmodel it should manipulate.

You can create delegatecommand ( or relaycommand ) using lambdas. Rather or as well as passing in an instance of mainwindowviewmodel these could potentially capture variables from wherever they are constructed. You could make that a mediator or event aggregator which abstracted UI services.

Essentially though.

These commands do what your click handlers do.

These lists of commands are your various switchable levels.

You work with these and bind them to the UI to template into a bunch of buttons.

The way you do that templating is in an itemscontrol. Or a listbox if you wanted to have a built in slider and maybe indicate which one was clicked last using selecteditem.

<ItemsControl ItemsSource="{Binding Commands}"
              >
    <ItemsControl.ItemTemplate>
        <DataTemplate DataType="{x:Type local:CommandViewModel}">
            <Button Content="{Binding Name}" 
                    Command="{Binding Command}"
                    CommandParameter="{Binding DataContext, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
                    >
            </Button>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

With the above a viewmodel which is the datacontext of this itemscontrol ( usually also of the entire window ) would have a public property which was an observablecollection of CommandViewModel. The items or the entire collection are switched out depending on the "level" chosen. You click one command which chooses Surveys and a list of commandviewmodel appropriate for Surveys are shown. One of those looks like it'd be a "Back" command which switched back to the previous list. And so on.

You could also have a property in a commandviewmodel which binds to Visibility so you could collapse a button. I'm not sure you'd need that with this pattern though. It will automatically cope with a "level" which has 3, 5, 10 or whatever number of commands.

You will have a fair bit of reading to do before you would be in a position to switch from your current pattern to mvvm. Delegatecommand is just one of your options, it's from Prism and there's a prism.mvvm nuget you could consider. Or you might prefer mvvmlight which has relaycommand. You'll want to use one of these or some other such framework to save you writing your own icommand implementation.

I hope that's sufficient to at least get you started.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM