开发者

Bind a views DialogResult to a ViewModels property?

开发者 https://www.devze.com 2023-03-14 05:54 出处:网络
I am relatively new to WPF, XAML and Data-bindings. I have a view (Window) and a view-model. I have tried to implement the MVVM pattern which means neither the view nor the view-model hold a referenc

I am relatively new to WPF, XAML and Data-bindings. I have a view (Window) and a view-model.

I have tried to implement the MVVM pattern which means neither the view nor the view-model hold a reference to each other. All data exchange happens via data-bindings.

So far so good but now I have run into a problem I can't find a solution for.

On my view I have a button Start which is bound to a command.

<Button Command="{Binding NextCommand}" Content="Next">

NextCommand is of type ActionCommand : ICommand

In my case NextCommand simply calls a private method within the view-model.

The problem I can not find a solution so far is the following:

How to close the window at the end of the view-models NextCommandAction method?

private void NextCommandAction(object o)
{
    ...
    ...
    // close the window
}

Since I do not have a reference to the view I can not just set DialogResult = true;

The only working solution I have found so far is to add a hidden radio-button to the view and bind it's开发者_StackOverflow社区 value to a property CloseView and create a method CloseView within the xaml.cs file which is bound to the Checked event of the hidden radio-button. Within that method I set DialogResult = true;

Although this works I feel like there has to be a better solution than adding hidden elements to your view!


You can pass the window reference as CommandParameter to the Close command and do whatever required on the window.

<Button Content="Close" Command="{Binding Path=CloseCommand}" 
  CommandParameter="{Binding ElementName=Window}"/>

private void CloseCommand(object sender)
{
    Window wnd = sender as Window;
    wnd.Close();
}


CommandParameter="{Binding ElementName=Window}" assumes that you have an element in your XAML named "Window". e.g, your Window tag would need Name="Window"


This question was one of the first things that came up when I googled to check if DialogResult is a dependency property (it isn't :-) )

Add a dependency property to your Window:

 public static readonly DependencyProperty InteractionResultProperty =
            DependencyProperty.Register(
                nameof(InteractionResult),
                typeof(Boolean?),
                typeof(MyWpfWindow1),
                new FrameworkPropertyMetadata(default(Boolean?), 
                    FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                    OnInteractionResultChanged));

  public Boolean? InteractionResult
        {
            get => (Boolean?) GetValue(InteractionResultProperty);
            set => SetValue(InteractionResultProperty, value);
        }

        private static void OnInteractionResultChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((MyWpfWindow1) d).DialogResult = e.NewValue as Boolean?;
        }

I named my property InteractionResult though a good name would have also worked.

In the xaml right after the you can bind it with a style


 <Window.Style>
        <Style TargetType="{x:Type z:MyWpfWindow1}">
            <Setter Property="InteractionResult"
                    Value="{Binding UpdateResult}" />
        </Style>
    </Window.Style>

UpdateResult is the property in my viewmodel.

  private Boolean? _updateResult;

        public Boolean? UpdateResult
        {
            get => _updateResult;
            set => SetValue(ref _updateResult, value);
        }

The SetValue method is the usual notify property

 protected virtual Boolean SetValue<T>(ref T field, T value, 
            [CallerMemberName]String propertyName = null)
        {
            if (Equals(field, value))
                return false;

            field = value;

            RaisePropertyChanged(propertyName);
            return true;
        }

and the property gets set in the usual way

<Button Content="Cancel" 
        Command="{Binding CancelCommand}" />

ICommand CancelCommand { get; }


private void OnCancel()
{
   UpdateResult = false;
}

Disclaimer: works on my computer.


Inspired by Chandrashekhar Joshi's answer (but not using the elements's name):

Define CommandParameter in Button:

<Button
  Command="{Binding CloseCommand}"
  CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=Window}}"
  Content="Close" />

Define Command (and Implementation):

CloseCommand = new DelegateCommand<Window>((w) => w.DialogResult = true);
0

精彩评论

暂无评论...
验证码 换一张
取 消