I have a problem with my small WPF tray icon which has a context menu assigned. If I do a right-click on the tray icon the context menu opens and you see a text box containing an integer value. Now when clicking to the "Create Instance" field the integer should increment by one. The new value should be shown in the textbox. On startup the correct inital value is shown in the textbox but changes during runtime are not reflected to the UI. I think there is a data binding problem... The click event is caught and even the value is incremented but the textbox does not recognize the new value...
I have no Main Window the application should only be a tray icon context menu.
App.xaml.cs
public partial class App : Application
{
// This objects are global
private TaskbarIcon notifyIcon;
private INotificationBarMessage message = null;
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
//create the notifyicon (a resource declared in NotifyIconResources.xaml)
notifyIcon = (TaskbarIcon) FindResource("Key_NotifyIcon");
notifyIcon.DataContext = this;
message = new NotificationBarMessage(notifyIcon);
message.Show(TextType.Startup);
}
}
ResourceContextMenu.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:tb="http://www.hardcodet.net/taskbar"
xmlns:local="clr-namespace:UserInterface.ViewModel"
x:Class="UserInterface.ViewModel.EventHandlerUI">
<ContextMenu x:Shared="false" x:Key="My_ContextMenu">
<ContextMenu.DataContext>
<local:ContextMenuModel /> <!-- reference to ContextMenuModel.cs -->
</ContextMenu.DataContext>
<!-- DataContext="{Binding PlacementTarget.DataContext,
RelativeSource={RelativeSource Self}} -->
<ContextMenu.Resources>
<local:ConverterBoolToVisibility x:Key="BoolToHiddenConverter"
TrueValue="Visible"
FalseValue="Hidden" />
<local:ConverterIntToString x:Key="IntToStringConverter" />
</ContextMenu.Resources>
<TextBlock Text="Status"/>
<Separator/>
<MenuItem Header="Create Instance"
MouseEnter="CreateInstance_OverEnter"
MouseLeave="CreateInstance_OverExit"
Click="CreateInstance_Click"
StaysOpenOnClick="True" />
<!-- Command="{Binding ShowWindowCommand}" -->
<MenuItem Header="Open Window"
StaysOpenOnClick="True"
Command="{Binding Commands.ShowWindowCommand}" />
<MenuItem Header="IP-Address"
Name="MenuItem_IPAddress"
Visibility="{Binding EventData.IsEnabled, Mode=TwoWay,
Converter={StaticResource BoolToHiddenConverter}}"
StaysOpenOnClick="True"/>
<TextBox Width="100"
Text="{Binding Path=EventData.Counter,
UpdateSourceTrigger=PropertyChanged, Mode=TwoWay,
Converter={StaticResource IntToStringConverter}}"/>
<Separator/>
<MenuItem Header="Exit"
Command="{Binding Path=Commands.ExitApplicationCommand}" />
</ContextMenu>
<!-- Tray Icon -->
<!-- the application's NotifyIcon - started from App.xaml.cs.
Declares its own view model. -->
<tb:TaskbarIcon x:Key="Key_NotifyIcon"
x:Name="My_NotifyIcon"
IconSource="/View/gfx/_UserInterface.ico"
ToolTipText="tip"
ContextMenu="{StaticResource My_ContextMenu}"/>
App.xaml
<Application x:Class="UserInterface.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
ShutdownMode="OnExplicitShutdown">
<Application.Resources>
<!-- Note that this application does not have a StartupUri declared,
so no Window is automatically loaded.
Also, the ShutdownMode was set to explicit,
so we have to close the application programmatically. -->
<!-- merge NotifyIcon and related stuff into the application -->
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ResourceContextMenu.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Here is the code where I fire the property changed event:
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private int _counter = 34;
public int Counter
{
get
{
return this._counter;
}
set
{
if (value != this._counter)
{
this._counter = value;
NotifyPropertyChanged();
}
}
}
Any help would be appreciated.
Related
I have built an application in MVVM using Caliburn Micro. I currently have the closetab working on all my tabs, and it closes all tabs apart from the first three, which are Home, Payment, Notes however, I would like it to NOT show the close tab icon on the first three tabs as shown in my AppViewModel code:
<TabControl x:Name="Items" Grid.Row="1" Visibility="{Binding Visibility, Converter={StaticResource boolToVis}}">
<TabControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<!-- The Tab Names Binding with DisplayName-->
<TextBlock Text="{Binding DisplayName}" />
<!-- The Tab Close Icon-->
<Button Content="x" x:Name="CloseTab" cal:Message.Attach="CloseTab" Style="{DynamicResource appTabCloseButton}" Visibility="{Binding Visibility, Converter={StaticResource boolToVis}}"/>
</StackPanel>
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
My AppViewModel code behind for the close tab:
public void CloseTab()
{
if(ActiveItem.DisplayName == "Home" || ActiveItem.DisplayName == "Payment" || ActiveItem.DisplayName == "Notes")
{
MessageBox.Show("This Tab Cannot Be closed.","Permanent Tab");
} else {
DeactivateItem(ActiveItem, close: true);
}
}
My App.xaml code for the boolToVis:
<Application x:Class="WPF.Test.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WPF.Test.App">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary>
<local:Bootstrapper x:Key="bootstrapper" />
<BooleanToVisibilityConverter x:Key="boolToVis" />
</ResourceDictionary>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Global.WPF.UserControls;component/Resources/brushes.xaml" />
<ResourceDictionary Source="/Global.WPF.UserControls;component/Resources/CommonControls.xaml" />
<ResourceDictionary Source="/Global.WPF.UserControls;component/Resources/menuItems.xaml" />
<ResourceDictionary Source="pack://application:,,,/Fluent;Component/Themes/Generic.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
and finally the visibility for the binding:
bool _visibility;
public bool Visibility
{
get { return _visibility; }
set
{
_visibility = value;
NotifyOfPropertyChange("Visibility");
}
}
I would be happy for any suggestions as I'm totally lost!!
Create a Guard Panel that can be used to show/hide the button.
<TabControl x:Name="Items" Grid.Row="1" Visibility="{Binding Visibility, Converter={StaticResource boolToVis}}">
<TabControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<!-- The Tab Names Binding with DisplayName-->
<TextBlock Text="{Binding DisplayName}" />
<Border x:Name="CanCloseTab">
<!-- The Tab Close Icon-->
<Button Content="x" x:Name="CloseTab" cal:Message.Attach="CloseTab" Style="{DynamicResource appTabCloseButton}" />
</Border>
</StackPanel>
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
Then create a guard property
public bool CanCloseTab {
get {
return !(ActiveItem.DisplayName == "Home"
|| ActiveItem.DisplayName == "Payment"
|| ActiveItem.DisplayName == "Notes");
}
}
By convention the view should automatically bind the CanCloseTab property to the visibility of the panel (Border) so that when false it will not display. If the panel was not there the guard property would have also automatically disabled the button.
This should now allow the CloseTab method to be refactored for simplicity.
public void CloseTab() {
if(CanCloseTab) {
DeactivateItem(ActiveItem, close: true);
}
}
I got a ResourceDictionary in my WPF project. The entire project is meant to be running in background. In ResourceDictionary there is a context menu, code is here;
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Commands="clr-namespace:_365Drive.Office365.NotificationManager"
xmlns:tb="http://www.hardcodet.net/taskbar"
xmlns:local="clr-namespace:_365Drive.Office365.NotificationManager">
<LinearGradientBrush x:Key="MenuBackground" EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="White" Offset="1" />
<GradientStop Color="White" Offset="0.259" />
</LinearGradientBrush>
<ContextMenu x:Shared="false" x:Key="SysTrayMenu" Name="contextMenu">
<MenuItem Header="Sign in" Command="{Binding ShowAuthForm}" CommandParameter="{Binding}" />
<MenuItem Header="Prompt MFA now" Name="MFA" Command="{Binding ClearMFACacheCommand}" CommandParameter="{Binding}" Visibility="{Binding MFAVisibility}" />
<MenuItem Header="Sign out" Command="{Binding SignOutApplicationCommand}" CommandParameter="{Binding}" />
<Separator />
<MenuItem Header="Update Drive Mappings" Command="{Binding RefreshSettingsCommand}" CommandParameter="{Binding}" />
<Separator />
<MenuItem Header="Exit" Command="{Binding ExitApplicationCommand}" />
</ContextMenu>
</ResourceDictionary>
The code behind of it is as follows (Snippet of code only)
public class NotifyIconViewModel
{
private Visibility visibility = Visibility.Collapsed;
public Visibility MFAVisibility
{
get
{
return ((1) == null ? Visibility.Collapsed : Visibility.Visible);
}
set
{
visibility = value;
}
}
}
There is other code in the code behind but that is irrelevant for this question.
I want to update the above property value from other class in the same project but I am not sure how can I get the instance of that class which is bound with the contextMenu.
And if I do try to set the MenuItem Visibility using code like below, it doesnt work;
public static void DisableMFAMenuitem()
{
System.Windows.Controls.ContextMenu ctxMenu = (System.Windows.Controls.ContextMenu)System.Windows.Application.Current.FindResource("SysTrayMenu");
System.Windows.Controls.ItemCollection items = ctxMenu.Items;
System.Windows.Controls.MenuItem itemtobeRemoved = null;
foreach (var item in items)
{
if (item.GetType() == typeof(System.Windows.Controls.MenuItem))
{
// do your work with the item
if (((System.Windows.Controls.MenuItem)item).Name == "MFA")
{
((System.Windows.Controls.MenuItem)item).Visibility = Visibility.Collapsed; // OR WHATEVER really
}
}
}
}
I think I am doing some small mistake in understanding, can anyone help here please?
Comment from Grx70 above helped.
I'm not sure I understand what you're trying to achieve here, but from
the first glimpse my guess would be that the troublemaker is the
x:Shared="False" attribute set on your resource, which means that each
FindResource("SysTrayMenu") call will yield a new ContextMenu instance
(so you're not modifying any pre-existing instance).
I am implementing a Download UI in WPF, where every file that is being downloaded will be shown inside a list box in a DataTemplate
<ListBox>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock x:Name="FileName" text={Binding FileName}" />
<ProgressBar ... />
<Button Content="Cancel" click="ButtonCancel_Click" />
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox>
Now this List is getting populated with all the download information perfectly. Only problem I am having is that when user clicks on Cancel button, to cancel the download, I have to remove an entry from the ObservableCollections. But I don't have the File Name in the click event( I know click event is not MVVM, still I want to do it in click event handler).
Can anyone suggest how do I get the FileName of that particular file when the selectedItem gets cancelled. in The
private void ButtonCancel_Click(...) {}
Although I would still encourage you to use MVVM way of dealing with UI events, here's how you can achieve what you want, using Cancel button's click event handler.
First in your xaml, bind file name to Cancel button's Tag property.
<ListBox>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock x:Name="FileName" text={Binding FileName}" />
<ProgressBar ... />
<Button Content="Cancel" Tag="{Binding FileName}"
Click="ButtonCancel_Click" />
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox>
Then in your click event handler
private void ButtonCancel_Click(object sender, RoutedEventArgs e)
{
Button myButton = (Button)sender;
string fileName = myButton.Tag.ToString();
// use fileName
}
Edit
Just to add a complete example, that was tested locally, and ensured that works.
XAML
<Window x:Class="WpfTestApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ListBox Name="listBox1">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock x:Name="FileName" Text="{Binding Path=FileName}" />
<Button Content="Cancel" Tag="{Binding Path=FileName}"
Click="ButtonCancel_Click" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
Code-behind
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var fileNames = new List<DownloadModel>
{
new DownloadModel
{
FileName = "File1"
},
new DownloadModel
{
FileName = "File2"
},
new DownloadModel
{
FileName = "File3"
}
};
listBox1.ItemsSource = fileNames;
}
private void ButtonCancel_Click(object sender, RoutedEventArgs e)
{
var myButton = sender as Button;
if (myButton.Tag == null)
{
MessageBox.Show("Tag value was null.");
}
else
{
MessageBox.Show(string.Format("File name is {0}", myButton.Tag));
}
}
}
public class DownloadModel
{
public string FileName { get; set; }
}
I would like to implement a dynamical menu in my application, written in C# and using WPF.
MenuSubSerialPortSelect.Items.Clear();
foreach (string element in GlobalVars.ActualSerialPorts)
{
MenuItem item = new MenuItem();
item.Header = element;
MenuSubSerialPortSelect.Items.Add(item);
}
The sub-menu adding is functional, but how can I add some radio buttons in this style?
I've read some websites that described that there must be used another "template", but I can't find a matched solution for me.
The attribute item.IsCheckable = true; is not a solution for me -- the entries must be blocked against each other.
It would be great if somebody could give me a tip on how to do that.
Try this
<Window x:Class="Stackoverflow.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Stackoverflow"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<RadioButton x:Key="RadioButton" HorizontalAlignment="Center"
GroupName="MyGroup" IsHitTestVisible="False"/>
<Style TargetType="MenuItem">
<Setter Property="Icon" Value="{StaticResource RadioButton}"/>
<EventSetter Event="Click" Handler="MenuItem_Click" />
</Style>
</Window.Resources>
<Grid Background="Red">
<Grid.ContextMenu>
<ContextMenu>
<MenuItem Header="Print"/>
<MenuItem Header="Save"/>
<MenuItem Header="Open"/>
<MenuItem Header="Delete"/>
<MenuItem Header="Update"/>
</ContextMenu>
</Grid.ContextMenu>
</Grid>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new ViewModel();
}
private void MenuItem_Click(object sender, System.Windows.RoutedEventArgs e)
{
MenuItem menuItem = sender as MenuItem;
if (menuItem != null)
{
RadioButton rb = menuItem.Icon as RadioButton;
if (rb != null)
{
rb.IsChecked = true;
}
}
}
}
Here i just have static menuitems.
This is the required behaviour:
I have various controls present on the canvas e.g. Callouts (from Expression Blend .dll), or simple Labels. When the user 'double clicks' (or any other event I decide to tie in) the control should change its appearance to allow the user to edit the control's Content property. Clicking off the control should then turn it back to 'read-only' method.
Any suggestions on how this would be best achieved? Ideally I want to do this all in c# to add this behaviour to the control at runtime (as this control is added dynamically to the canvas)- and avoid XAML altogether.
I reckon I've got to do something with adorners to display a textbox bound to the control's content property on the required event, but some code samples or links elsewhere would be appreciated? :) - I haven't been able to find anything on an existing search, but I reckon it should be fairly simple.
Unfortunately, style triggers do not do anything with IsReadOnly and IsEnabled. You would have to do that from an event.
Here is my sample:
WPF:
<Window x:Class="StateChangingTextbox.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="#eee" />
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBox Width="300" Height="200" TextWrapping="Wrap" IsReadOnly="True"
MouseEnter="TextBox_MouseEnter"
MouseLeave="TextBox_MouseLeave"/>
</Grid>
</Window>
Code-behind:
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void TextBox_MouseEnter(object sender, MouseEventArgs e)
{
var textbox = sender as TextBox;
if (textbox != null)
{
textbox.IsReadOnly = false;
}
}
private void TextBox_MouseLeave(object sender, MouseEventArgs e)
{
var textbox = sender as TextBox;
if (textbox != null)
{
textbox.IsReadOnly = true;
}
}
}
XAML:
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ed="http://schemas.microsoft.com/expression/2010/drawing"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
mc:Ignorable="d"
x:Class="ComicWPF.Bubble"
x:Name="UserControl" Height="100" Width="200">
<Canvas LostFocus="this_LostFocus">
<ed:Callout x:Name="callout" Content=""
AnchorPoint="0,1" FontSize="14" Height="100" Width="200"
Fill="Blue"
PreviewMouseDoubleClick="Callout_DoubleClick"
Canvas.Left="0" Canvas.Top="0" />
<TextBox x:Name="textbox"
FontSize="14"
Canvas.Left="30" Height="55" Width="80" Canvas.Top="30"
Visibility="Visible"/>
</Canvas>
</UserControl>
C# Code:
private void Callout_DoubleClick(object sender, MouseButtonEventArgs e)
{
Activate();
}
public void Activate()
{
//set bool activated to true
//make textbox visible and set focus and select all text
}
private void Callout_DeSelect()
{
//set content of callout to the textbox.Text
//Hide textbox
//set bool activated to false
}
private void this_LostFocus(object sender, RoutedEventArgs e)
{
Callout_DeSelect();
}
}