سؤال

Hy,

I have a menu with a few menu items. I have various other elements like a treeview and some controls. When I open the program all elements in the menu are available. But the first step I have to do is to connect to the server. So all the the other elements shouldn't available till there is made a connection via the connection menu item.

Then I want to show only menu items if a special tree view (for instance the whole item structure) item is choosen for instance all topics. For instance there should be special menu items available if I click a treeview entry in the menu.

Is it possible to accomplish this in xaml?

Update1:

MainWindow.xaml

Title="Service Bus Visualizer" Height="680" Width="1200" Name="Root"
<MenuItem Header="_Read File" Name="readFile" Click="MenuItemReadFile" HorizontalAlignment="Right" Width="187" IsEnabled="{Binding Path=DataContext.IsMonitoring, ElementName=Root}">
    <MenuItem.Icon>
        <Image Source="Icons/Open.ico" Width="16" Height="16" />
    </MenuItem.Icon>
</MenuItem>

MainWindow.xaml.cs

public bool IsMonitoring
{
    get
    {
        return isMonitoring;
    }
    set
    {
        isMonitoring = value;
        RaisePropertyChanged("IsMonitoring");
    }
}

private bool isMonitoring;
public MainWindow()
{
    InitializeComponent();
    this.IsMonitoring = false;
    this.DataContext = this;
    Application.Current.MainWindow = this;
}

public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string name)
{
    if (PropertyChanged != null)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(name));
    }
}

ConnectionWindow.xaml.cs

MainWindow mainWindow = Application.Current.MainWindow as MainWindow;
mainWindow.IsMonitoring = true;

I get no error on the output window but it doesn't work?

Update2:

I have a second parameter which is a ObservableCollection.

MainWindow.xaml

<ListBox Grid.Row="3" Name="Logger" ItemsSource="{Binding Path=DataContext.LoggingList, ElementName=Root}" DisplayMemberPath="Message" IsSynchronizedWithCurrentItem="True" ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollBarVisibility="Visible" SelectionChanged="BringSelectionIntoView">
</ListBox>

MainWindow.xaml.cs

public static ObservableCollection<Log> LoggingList { get; set; }

public MainWindow()
{
    LoggingList = new ThreadSafeObservableCollection<Log>();
    this.IsMonitoring = false;
    this.DataContext = this;
    Application.Current.MainWindow = this;
    InitializeComponent();
}

Log.cs

public class Log : INotifyPropertyChanged
{
    public string Message {
        get
        {
            return message;
        }
        set
        {
            message = value;
            NotifyPropertyChanged("Message");
        }
    }
    public string message;

    public Log()
    {
    }

    public Log(string message)
    {
        this.Message = message;
        NotifyPropertyChanged("Message");
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void NotifyPropertyChanged(string name)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(name));
    }        
}

Best regards

هل كانت مفيدة؟

المحلول

First, you have two options as far as "availability" is concerned. The "IsEnabled" property, and the "Visible" property. "IsEnabled" is a bool, and determines if the user can click/select/interact with a given element. Generally speaking, if this property is set to false the element will appear "greyed out".

Changing Visibility will make the element appear/disappear entirely. When set to "Visible" (this is actually an enum), it appears normally. When set to "Hidden", the space for it is reserved on the UI, but you can't actually see it. When set to "Collapsed" you cannot see it and no space is reserved for it in the layout.

For your first requirement (waiting to connect to the server), I would use IsEnabled bound to a "IsConnected" property like so:

IsEnabled="{Binding IsConnected}"

That would go on each item that needs to have this behavior.

The "context-specific" menu items are a bit more complicated, but the basic idea would be a binding on Visible for each of the context sensitive items like:

Visible="{Binding Path=SelectedItem, ElementName=MyTreeView, Converter={StaticResource SelectedItemToVisibilityConverter}, ConverterParameter={x:Type ChildItem}"

I am assuming that each items visibility depends on what type of item is selected (child or parent), you should be able to extend the example if I was wrong. The converter would then look like:

public class SelectedItemToVisibilityConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if ((parameter as Type).IsInstanceOfType(value))
            return Visibility.Visible;
        else
            return Visibility.Collapsed;
    }

    public object ConvertBack(...)
    {
         return Binding.DoNothing;
    }
}

Please let me know if I can clarify anything. Hopefully that gives you a good starting point for what you are trying to do.

Update:

Looking at your code I see a couple potential problems:

  1. IsMonitoring is declared as a public field. Binding only works with public properties. This property needs to raise the PropertyChanged event for it to work.
  2. In "MainWindow.xaml.cs" you are setting the DataContext multiple times. This isn't how DataContext works in WPF. You need to set it to one object (your ViewModel) that contains all the properties you are interested in binding to. While it is considered bad practice, you could write this.DataContext = this to get it working before you build a ViewModel class.
  3. The IsMonitoring field is declared in your "MainWindow.xaml.cs" file. First, this should be in a view model. Second, the binding is looking for that property on the MenuItem class (likely because it is in some sort of ItemsControl). If you want it on the root data context, give your window some name (like "Root") and use the following binding:

    "{Binding Path=DataContext.IsMonitoring, ElementName=Root}"
    

Hopefully that makes sense. Let me know if I can help further!

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top