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);
精彩评论