Привязка WPF к свойству IsEnabled в элементе MenuItem ContextMenu ListBox

я просматривал другие темы, касающиеся привязки данных к контекстным меню, но я не мог понять, как заставить его работать, поскольку предложения/ответы не работали для меня.

у меня есть список, который привязан к ObversableCollection - отлично работает.

теперь у меня есть контекстное меню внутри этого списка. это контекстное меню имеет 4 элемента для активации, деактивации и т. д. выбранной задачи (это элемент, представленный в списке).

из-за разрешений мне нужно контролировать, включены ли элементы в contextmenu или отключены, поэтому я должен установить IsEnabled-Property ContextMenuItem, привязав его к той же коллекции, к которой привязан Listbox.

но по какой-то причине элементы контекстного меню не отключаются - свойство, похоже, игнорируется.


EDIT: теперь я реализовал ваше предложение:

WPF

<ListView Margin="10,10,10,55" Name="listviewCurrentJobs" ItemsSource="{Binding JobCollection}">
    <ListView.ContextMenu>
        <ContextMenu>
            <MenuItem Header="Starten" Command="{Binding Path=startCommand}"/>
            <MenuItem Header="Stoppen" Command="{Binding Path=stopCommand}"/>
            <MenuItem Header="Aktivieren" Command="{Binding Path=enableCommand}"/>
            <MenuItem Header="Deaktivieren" Command="{Binding Path=disableCommand}"/>
            <MenuItem Header="Löschen" Command="{Binding Path=deleteCommand}"/>
        </ContextMenu>
    </ListView.ContextMenu>
    <ListView.View>
        <GridView>
            <GridViewColumn Header="" Width="32">
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <Image Source="{Binding State}" Width="16"/>
                        </StackPanel>
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
            </GridViewColumn>
            <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Description}" />
        </GridView>
    </ListView.View>
</ListView>

C#

public class currentJob : MonitoringWindow
{
    public string State { get; set; }
    public string Description { get; set; }

    public bool startPermitted { get; set; }
    public bool stopPermitted { get; set; }
    public bool enablePermitted { get; set; }
    public bool disablePermitted { get; set; }
    public bool deletePermitted { get; set; }

    public ICommand StartCommand { get; private set; }
    public ICommand StopCommand { get; private set; }
    public ICommand EnableCommand { get; private set; }
    public ICommand DisableCommand { get; private set; }
    public ICommand DeleteCommand { get; private set; }

    public currentJob()
    {
        StartCommand = new DelegateCommand(ExecuteStart, CanExecuteStart);
        StopCommand = new DelegateCommand(ExecuteStop, CanExecuteStop);
        EnableCommand = new DelegateCommand(ExecuteEnable, CanExecuteEnable);
        DisableCommand = new DelegateCommand(ExecuteDisable, CanExecuteDisable);
        DeleteCommand = new DelegateCommand(ExecuteDelete, CanExecuteDelete);
    }

    public bool CanExecuteStart()
    {
        return startPermitted;
    }
    public bool CanExecuteStop()
    {
        return stopPermitted;
    }
    public bool CanExecuteEnable()
    {
        return enablePermitted;
    }
    public bool CanExecuteDisable()
    {
        return disablePermitted;
    }
    public bool CanExecuteDelete()
    {
        return deletePermitted;
    }

    public void ExecuteStart()
    {
        currentJob curJob = ((currentJob)listviewCurrentJobs.SelectedItem);
        string curJobName = curJob.Name;
        if (new TaskService().GetFolder("DocuWare Notifications").Tasks[curJobName].Enabled == false)
            new TaskService().GetFolder("DocuWare Notifications").Tasks[curJobName].Enabled = true;
        new TaskService().GetFolder("DocuWare Notifications").Tasks[curJobName].Run();
        loadJobs();
    }
    public void ExecuteStop()
    {
        if (new TaskService().GetFolder("DocuWare Notifications").Tasks[((currentJob)listviewCurrentJobs.SelectedItem).Name].Enabled == true)
        {
            new TaskService().GetFolder("DocuWare Notifications").Tasks[((currentJob)listviewCurrentJobs.SelectedItem).Name].Stop();
            loadJobs();
        }
    }
    public void ExecuteEnable()
    {
        new TaskService().GetFolder("DocuWare Notifications").Tasks[((currentJob)listviewCurrentJobs.SelectedItem).Name].Enabled = true;
        loadJobs();
    }
    public void ExecuteDisable()
    {
        new TaskService().GetFolder("DocuWare Notifications").Tasks[((currentJob)listviewCurrentJobs.SelectedItem).Name].Enabled = false;
        loadJobs();
    }
    public void ExecuteDelete()
    {
        new TaskService().GetFolder("DocuWare Notifications").DeleteTask(((currentJob)listviewCurrentJobs.SelectedItem).Name);
        if (isMsSql)
        {
            mssqlconn.Open();
            new SqlCommand("DELETE FROM dbo.DocuWareNotifications WHERE NAME = '" + ((currentJob)listviewCurrentJobs.SelectedItem).Name + "'", mssqlconn).ExecuteNonQuery();
            mssqlconn.Close();
        }
        else
        {
            mysqlconn.Open();
            new MySqlCommand("DELETE FROM DocuWareNotifications WHERE NAME = '" + ((currentJob)listviewCurrentJobs.SelectedItem).Name + "'", mysqlconn).ExecuteNonQuery();
            mysqlconn.Close();
        }
        loadJobs();
    }
}

public partial class MonitoringWindow : MetroWindow
{
    [...]
    foreach (Task task in new TaskService().GetFolder("DocuWare Notifications").Tasks)
    {
        if (task != null)
        {
            currentJob item = new currentJob();
            switch (task.State)
            {
                case TaskState.Disabled:
                    item.State = "/DWNotDesigner;component/images/disabled.png";
                    item.Description = task.Name;
                    break;
                case TaskState.Ready:
                    item.State = "/DWNotDesigner;component/images/active.png";
                    item.Description = task.Name;
                    break;
                case TaskState.Running:
                    item.State = "/DWNotDesigner;component/images/working.png";
                    item.Description = task.Name;
                    break;
            }
            item.startPermitted = startPermitted;
            item.stopPermitted = stopPermitted;
            item.enablePermitted = enablePermitted;
            item.disablePermitted = disablePermitted;
            item.deletePermitted = deletePermitted;
            _jobCollection.Add(item);
        }
    }
}

почему-то нет изменений!


person Jens Langenbach    schedule 16.08.2013    source источник


Ответы (1)


Вы можете попробовать использовать привязки команд (вам понадобится prism):

...
<ContextMenu DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
    <MenuItem Command="{Binding StartCommand}"/>
    ...
</ContextMenu>
...

...

using Microsoft.Practices.Composite.Presentation.Commands;

public class currentJob
{
    public ICommand StartCommand {get; private set;}
    public currentJob ()
    {
         StartCommand = new DelegateCommand(ExecuteStart, CanExecuteStart); 
    }

    private bool CanExecuteStart()
    {
        //Determine whether start can be executed
        return true;
    }

    private void ExecuteStart()
    {
        //start here
    }
}

Здесь ExecuteStart заменяет startJob, а CanExecuteStart заменяет enablePermitted в исходном примере.


Изменить Возможно, это поможет объяснить, почему исходный код не работает. Изменения связанных свойств вступают в силу только в том случае, если событие "PropertyChange" запускается объектом свойства. Реализация INotifyPropertyChanged, вероятно, также решит вашу проблему.


Редактировать Еще более тривиальная проблема с исходным кодом заключается в том, что он привязывается к неправильному объекту. Я предполагаю, что в FeedContextMenu не существует свойства startPermitted (которое в любом случае не определено).


Редактировать Есть еще несколько проблем выше: 1) привязки чувствительны к регистру, поэтому привязка должна быть {Binding StartCommand} и т. д. 2) Вам нужно установить контекстное меню для отдельных элементов в список. Следующее будет работать:

    <ListView Margin="10,10,10,55" Name="listviewCurrentJobs" ItemsSource="{Binding JobCollection}">
        <ListView.ItemTemplate>
                <DataTemplate>
                <Border BorderBrush="Black" BorderThickness="2">
                    <StackPanel Orientation="Horizontal" MinHeight="20" Background="White">
                        <StackPanel.ContextMenu>
                            <ContextMenu DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
                                <MenuItem Header="Starten" Command="{Binding Path=StartCommand}"/>
                                <MenuItem Header="Stoppen" Command="{Binding Path=StopCommand}"/>
                                <MenuItem Header="Aktivieren" Command="{Binding Path=EnableCommand}"/>
                                <MenuItem Header="Deaktivieren" Command="{Binding Path=DisableCommand}"/>
                                <MenuItem Header="Löschen" Command="{Binding Path=DeleteCommand}"/>
                            </ContextMenu>
                        </StackPanel.ContextMenu>
                        <Image Source="{Binding State}" Width="16"/>
                    </StackPanel>
                </Border>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
person mickeyt    schedule 16.08.2013
comment
это не отключит кнопку, не так ли? - person Jens Langenbach; 16.08.2013
comment
Если CanExecuteStart возвращает false, кнопка будет отключена. - person mickeyt; 16.08.2013
comment
теперь я обновил вопрос, он не работает до сих пор. - person Jens Langenbach; 16.08.2013
comment
См. редактирование привязки ContextMenu DataContext. Вы были почти там в первый раз! - person mickeyt; 16.08.2013
comment
к сожалению, он все еще не работает, для свойства isActive DelegateCommand установлено значение false, может ли это быть проблемой? я также видел, как люди в Интернете пытались вручную вызвать метод CanExecuteStart(), я этого не делаю - это правильный подход? - person Jens Langenbach; 16.08.2013