CommandParameter всегда равен NULL

Я хочу реализовать простую кнопку закрытия в окне WPF. Окно в основном выглядит так:

    <Window x:Class="MyApplication.MainWindow"
            xmlns=""....
            ...."
            Title="MainWindow" WindowState="Maximized" WindowStartupLocation="CenterScreen" x:Name="mainWindow">
<DockPanel LastChildFill="True">
        <Ribbon DockPanel.Dock="Top">
            <Ribbon.ApplicationMenu>
                <RibbonApplicationMenu SmallImageSource="Resources/menu_16x16.png">
                    <RibbonApplicationMenu.FooterPaneContent>
                        <RibbonButton Label="Beenden" 
                                      Command="{Binding CmdCloseApp}" 
                                      CommandParameter="{Binding ElementName=mainWindow}"
                                      SmallImageSource="Resources/ende_16x16.png" 
                                      HorizontalAlignment="Right"/>
                    </RibbonApplicationMenu.FooterPaneContent>
                </RibbonApplicationMenu>
            </Ribbon.ApplicationMenu>
        </Ribbon>
</DockPanel>
    </Window>

DataContext этого окна установлен в коде программной части как экземпляр MainWindowViewModel

MainWindowViewModel:

public class MainWindowViewModel
{
        public ICommand CmdCloseApp { get; set; }

        public MainWindowViewModel()
        {
            CmdCloseApp = new RelayCommand<Window>(CloseApp);
        }

        public void CloseApp(Window w)
        {
            w.Close();
        }
}

В CloseAppw всегда ноль. Все остальные команды со строковыми параметрами и т. Д. Работают отлично - моя единственная проблема в том, что я не получаю, что элемент окна не находит путь к моей модели просмотра.

Спасибо за вашу помощь!

ИЗМЕНИТЬ Мне очень жаль, я попробовал с помощью простой кнопки, и это сработало - проблема возникает только с RibbonButton


person CeOnSql    schedule 24.06.2016    source источник
comment
в commandParameter попробуйте привязать родительский элемент, а не имя окна.   -  person Rohit Prakash    schedule 24.06.2016
comment
Привет, я попробовал ваш образец, и у меня он отлично работает, я могу получить окно в качестве параметра в моей модели представления. Вы используете собственный код команды реле ??   -  person Sivasubramanian    schedule 24.06.2016
comment
@RohitPrakash спасибо за эту точку, я уже пробовал решение с FindAnchestor-, но остается нулевым   -  person CeOnSql    schedule 24.06.2016
comment
@Sivasubramanian Я получил свой класс RelayCommand из ответа на этот пост: stackoverflow.com/questions/22285866/why-relaycommand   -  person CeOnSql    schedule 24.06.2016
comment
извините ребята - вопрос редактирует. Он работал с кнопкой, но НЕ работал с RibbonButton. Я смущен...   -  person CeOnSql    schedule 24.06.2016


Ответы (1)


Изменить: после изменения меню приложения RibbonButton ваша проблема заключается в том, что Microsoft RibbonControlLibrary использует всплывающее меню для удержания кнопки, а MainWindow не является частью (родительским элементом) визуального дерева всплывающего меню, поэтому ваш Привязка ElementName не может найти окно "mainWindow", поэтому она присваивает значение null для CommandParameter
Вы можете использовать статический Application.Current для получения MainWindow, тогда он будет работать.
NB! MainWindow - это имя свойства приложения, а не имя вашего окна

<Window x:Class="WpfRelayCommandParameter.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:wpfRelayCommandParameter="clr-namespace:WpfRelayCommandParameter"
    xmlns:ribbon="http://schemas.microsoft.com/winfx/2006/xaml/presentation/ribbon"
    mc:Ignorable="d"
    d:DataContext="{d:DesignInstance wpfRelayCommandParameter:MainWindowViewModel}"
    Title="MainWindow" Height="350" Width="525"
    x:Name="mainWindow">
<DockPanel LastChildFill="True">
    <DockPanel LastChildFill="True">
        <ribbon:Ribbon DockPanel.Dock="Top">
            <ribbon:Ribbon.ApplicationMenu>
                <ribbon:RibbonApplicationMenu SmallImageSource="Resources/AppMenu.png">
                    <ribbon:RibbonApplicationMenu.FooterPaneContent>
                        <ribbon:RibbonButton Label="Beenden" 
                                  Command="{Binding CmdCloseApp}" 
                                  CommandParameter="{Binding MainWindow, Source={x:Static Application.Current}}"
                                  SmallImageSource="Resources/Exit.png" 
                                  HorizontalAlignment="Right" Click="ButtonBase_OnClick"/>
                    </ribbon:RibbonApplicationMenu.FooterPaneContent>
                </ribbon:RibbonApplicationMenu>
            </ribbon:Ribbon.ApplicationMenu>
        </ribbon:Ribbon>
    </DockPanel>
</DockPanel>

Personally I prefer callbacks to the window to go through an interface that can be custom to your view model needs, and can be mocked in unit tests:

<Window x:Class="WpfRelayCommandParameter.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:wpfRelayCommandParameter="clr-namespace:WpfRelayCommandParameter"
    mc:Ignorable="d"
    d:DataContext="{d:DesignInstance wpfRelayCommandParameter:MainWindowViewModel}"
    Title="MainWindow" Height="350" Width="525"
    x:Name="mainWindow">
<Grid>
    <Button Content="Close Window" 
            Command="{Binding CmdCloseApp}" 
            VerticalAlignment="Top"
            HorizontalAlignment="Left" />
</Grid>

Code

public partial class MainWindow : Window, IMainWindow
{
    public MainWindow()
    {
        DataContext = new MainWindowViewModel(this);
        InitializeComponent();
    }
}

public interface IMainWindow
{
    void Close();
}

public class MainWindowViewModel
{
    private readonly IMainWindow _mainWindow;

    public MainWindowViewModel() : this(null)
    {
        // Design time
    }

    public MainWindowViewModel(IMainWindow mainWindow)
    {
        _mainWindow = mainWindow;
        CmdCloseApp = new RelayCommand(CloseApp);
    }

    public ICommand CmdCloseApp { get; set; }

    public void CloseApp(object parameter)
    {
        _mainWindow.Close();
    }
}

Обратите внимание на возможные проблемы с типом и нулевым значением для CanExecute CanExecute в RelayCommand

person Michael    schedule 24.06.2016
comment
Спасибо, теперь работает (через интерфейс). Прекрасное объяснение, почему мое решение не сработало :) - person CeOnSql; 27.06.2016