When I click menu strip and then press shortcut key it works but it does not work otherwise. Is there something to set scope of shortcut key?
XAML:
<Window x:Class="NewGUI_WPF.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:common="clr-namespace:Common;assembly=RecentFileListLib"
Title="Sezor" Height="Auto" Width="Auto" WindowStartupLocation="Manual" Icon="/NewGUI_WPF;component/Images/i161.ICO" WindowStyle="SingleBorderWindow" Focusable="False" ResizeMode="CanResize" mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" d:DesignHeight="243" d:DesignWidth="314" SizeToContent="Manual" WindowState="Maximized">
<Window.CommandBindings>
<CommandBinding Command="Save" Executed="SaveCommand" />
<CommandBinding Command="Open" Executed="OpenCommand" />
</Window.CommandBindings>
<Grid>
<Menu Height="23" Name="main_menu" VerticalAlignment="Top" HorizontalAlignment="Stretch" IsMainMenu="True">
<MenuItem Name="MI_Case" Header="Case">
<MenuItem Header="Open" Command="Open">
<MenuItem.Icon>
<Image Height="16" Width="16" Source="/NewGUI_WPF;component/Images/openHS.png" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Save" Name="MainMenu_File_Save" Command="Save">
<MenuItem.Icon>
<Image Height="16" Width="16" Source="/NewGUI_WPF;component/Images/saveHS.png" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Save as" Name="MainMenu_File_SaveAs" Click="MainMenu_File_SaveAs_Click" />
<common:RecentFileList x:Name="RecentFileList" />
<MenuItem Header="Quit" Click="MainMenu_File_Quit_Click" />
</MenuItem>
<MenuItem Header="View">
<MenuItem Header="Input File" Click="MainMenu_View_InputFile_Click" />
<MenuItem Header="Mesh File" Click="MainMenu_View_meshFile_Click" />
<MenuItem Name="MainMenu_View_Summary" Header="Summary" Click="MainMenu_View_summary_Click" />
</MenuItem>
<MenuItem Header="Define" >
<MenuItem Header="Input File" Click="MainMenu_Define_InputFile_Click" Name="MainMenu_Define_InputFile" />
<MenuItem Header="Mesh File" Click="MainMenu_Define_MeshFile_Click" Name="MainMenu_Define_MeshFile" />
<MenuItem Header="Simulation File" Click="MainMenu_Define_SimulFile_Click" Name="MainMenu_Define_SimulFile" />
<MenuItem Header="Boundaries" Click="MainMenu_Define_BC_Click" />
<MenuItem Header="Initials" Click="MainMenu_Define_Initials_Click" />
<MenuItem Header="Spatial Discretization" Click="MainMenu_Define_SpatDis_Click" />
<MenuItem Header="Flow" Click="MainMenu_Define_Flow_Click" />
<MenuItem Header="Material" Click="MainMenu_Define_Material" />
<MenuItem Header="Algoritm" Click="MainMenu_Define_Algoritm" />
<MenuItem Header="Gradient Reconstruction">
<RadioButton Content="Least-Squares" Checked="Least_Squares_Checked" Name="rad_GR_LS" />
<RadioButton Content="Green-Gauss" Click="Green_Gauss_Checked" Name="rad_GR_GG" />
</MenuItem>
</MenuItem>
<MenuItem Header="Run" >
<MenuItem Header="Simulation" Click="MainMenu_Run_Simulation_Click" />
</MenuItem>
</Menu>
<Frame Height="Auto" HorizontalAlignment="Left" Margin="40,60,30,20" Name="frm_summary" VerticalAlignment="Top" Width="Auto" NavigationUIVisibility="Hidden" />
<StatusBar Height="23" Name="statusBar1" VerticalAlignment="Bottom" Margin="0">
<TextBlock Name="statBar_text_1"></TextBlock>
</StatusBar>
</Grid>
Code:
private void OpenCommand(object sender, ExecutedRoutedEventArgs e) {...}
private void SaveCommand(object sender, ExecutedRoutedEventArgs e) {...}
Remove Focusable="False" in your Window tag.
Looks like you need to add CanExecute to the CommandBinding and a corresponding code behind method.
Here's a minimal demonstration that wires up Control-S to launch the Help command.
The XAML:
<Window x:Class="stackoverflow___scope_of_menu_shortcut_key.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.CommandBindings>
<CommandBinding Command="Help" CanExecute="HelpCanExecute" Executed="HelpExecuted"/>
</Window.CommandBindings>
<Window.InputBindings>
<KeyBinding Command="Help" Key="S" Modifiers="Control"/>
</Window.InputBindings>
<Menu>
<MenuItem Header="File">
<MenuItem Header="Help" Name="HelpMenu" Command="Help"/>
</MenuItem>
</Menu>
</Window>
The code behind:
using System.Windows;
using System.Windows.Input;
namespace stackoverflow___scope_of_menu_shortcut_key
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void HelpCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
private void HelpExecuted(object sender, ExecutedRoutedEventArgs e)
{
System.Diagnostics.Process.Start("http://www.microsoft.com");
}
}
}
Notice that if you comment out the line:
e.CanExecute = true;
the key bindings no longer function.
Here's your example, stripped down to a bare minimum. This works on my system:
XAML:
<Window x:Class="stackoverflow___scope_of_menu_shortcut_key.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.CommandBindings>
<CommandBinding Command="Save" Executed="MyCommand" />
</Window.CommandBindings>
<MenuItem Header="Save" Command="ApplicationCommands.Save"/>
</Window>
Code behind:
using System.Windows;
using System.Windows.Input;
namespace stackoverflow___scope_of_menu_shortcut_key
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void MyCommand(object sender, ExecutedRoutedEventArgs e)
{
System.Diagnostics.Process.Start("http://www.microsoft.com");
}
}
}
Related
Project Informations
Windows Presentation Foundation Project
C# as programming language
Description
Is it possible to receive data from an user input in Window1 and show this input in MainWindow?
I will open the user input as a file from Window1 and will show the content of it in the RichTextBox of MainWindow.
Window1
<Window x:Name="window1" x:Class="Writer.Window1"
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:local="clr-namespace:Writer"
mc:Ignorable="d"
Title="New" Height="130" Width="600" WindowStyle="None" WindowStartupLocation="CenterScreen" ResizeMode="CanMinimize">
<Grid Margin="0,0,0,-2">
<Rectangle HorizontalAlignment="Center" Height="30" Stroke="Black" VerticalAlignment="Top" Width="600" Fill="Black"/>
<Label Content="Open" HorizontalAlignment="Left" Margin="0,2,0,0" VerticalAlignment="Top" Foreground="White"/>
<Button Content="X" Margin="579,5,10,0" VerticalAlignment="Top" Background="Black" Foreground="White" BorderBrush="Black" ToolTip="Exit" Focusable="False" IsTabStop="False" Click="Button_Click"/>
<Label Content="Select the path" HorizontalAlignment="Left" Margin="0,35,0,0" VerticalAlignment="Top"/>
<TextBox HorizontalAlignment="Left" Margin="5,61,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" IsTabStop="False"/>
<Button Content="Select" HorizontalAlignment="Left" Margin="5,84,0,0" VerticalAlignment="Top" BorderBrush="White" Background="#FFADADAD" Width="45"/>
</Grid>
</Window>
MainWindow
<Window x:Name="MainWindow1" x:Class="Writer.MainWindow"
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:local="clr-namespace:Writer"
mc:Ignorable="d"
Title="Writer" Height="450" Width="800" WindowStyle="None" WindowStartupLocation="CenterScreen" ResizeMode="CanMinimize">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="164*"/>
<RowDefinition Height="83*"/>
<RowDefinition Height="203*"/>
</Grid.RowDefinitions>
<Rectangle HorizontalAlignment="Center" Height="30" Stroke="Black" VerticalAlignment="Top" Width="800" Fill="Black"/>
<Label Content="Writer" HorizontalAlignment="Left" Margin="0,2,0,0" VerticalAlignment="Top" Foreground="White"/>
<Button Content="_" HorizontalAlignment="Left" Margin="765,5,0,0" VerticalAlignment="Top" Background="Black" Foreground="White" BorderBrush="Black" Focusable="False" ToolTip="Minimize" IsTabStop="False" ClickMode="Press" Click="Button_Click_1"/>
<Button Content="X" Margin="779,5,10,0" VerticalAlignment="Top" Background="Black" Foreground="White" BorderBrush="Black" ToolTip="Exit" Focusable="False" IsTabStop="False" Click="Button_Click"/>
<Menu Margin="0,30,0,114" Height="20">
<MenuItem Header="File">
<MenuItem Header="New">
<MenuItem.Icon>
<Image Source="/file-added.svg"/>
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Open" Click="MenuItem_Click"/>
<MenuItem Header="Open from server"/>
<MenuItem Header="Save"/>
<MenuItem Header="Save as"/>
<MenuItem Header="Close file"/>
<MenuItem Header="Close folder"/>
</MenuItem>
<MenuItem Header="Start">
<MenuItem Header="Font">
<MenuItem Header="Font"/>
<MenuItem Header="Family"/>
<MenuItem Header="Size"/>
</MenuItem>
<Separator/>
<MenuItem Header="Bold"/>
<MenuItem Header="Italic"/>
<MenuItem Header="Underline"/>
<MenuItem Header="Strikethrough"/>
</MenuItem>
<MenuItem Header="Insert">
<MenuItem Header="New site"/>
</MenuItem>
<MenuItem Header="Layout">
</MenuItem>
<MenuItem Header="View">
</MenuItem>
<MenuItem Header="Help"/>
</Menu>
<RichTextBox x:Name="RichTextBox1" Margin="0,50,0,0" BorderBrush="White" Cursor="Arrow" IsTabStop="False" Grid.RowSpan="3" FontFamily="Segoe UI" BorderThickness="0,0,0,0">
<FlowDocument>
<Paragraph>
<Run Text=""/>
</Paragraph>
</FlowDocument>
</RichTextBox>
</Grid>
</Window>
Yes, there is a way.
Implement a public method in Window1 that gives you the data.
Then use the reference to Window1 and call that method.
If MainWindow does not have a reference to Window1, give it the reference.
Here's an example. It assumes that you open the second window from within the main window.
In addition to the CC-BY-SA license of Stack Overflow, I license this as CC-0 for anyone who needs this code in one of his projects.
MainWindow.xaml
<Window x:Class="GetDataFromOtherWindow.MainWindow"
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"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<StackPanel>
<Button Content="Open other window" Click="Button_Click" />
<Button Content="Get data from other window" Click="Button_Click_1" />
</StackPanel>
</Window>
MainWindow.xaml.cs
using System.Windows;
namespace GetDataFromOtherWindow
{
public partial class MainWindow : Window
{
private Window1? otherWindow;
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
otherWindow = new Window1();
otherWindow.Show();
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
if (otherWindow != null)
{
MessageBox.Show(otherWindow.GetData());
}
}
}
}
Window1.xaml
<Window x:Class="GetDataFromOtherWindow.Window1"
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"
mc:Ignorable="d"
Title="Window1" Height="141" Width="400">
<StackPanel>
<RichTextBox Name="richBox">
<FlowDocument>
<Paragraph>
<Run Text="This is some text"/>
</Paragraph>
</FlowDocument>
</RichTextBox>
</StackPanel>
</Window>
Window1.xaml.cs
using System.Windows;
using System.Windows.Documents;
namespace GetDataFromOtherWindow
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
public string GetData()
{
TextRange textRange = new TextRange(
richBox.Document.ContentStart,
richBox.Document.ContentEnd
);
return textRange.Text;
}
}
}
Note that this is not very MVVM-friendly, because this code has no model which would know about the business logic.
As per the comments, if you want to show the data after closing Window1, you can do this:
MainWindow.xaml.cs
using System.Windows;
namespace GetDataFromOtherWindow
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var otherWindow = new Window1();
otherWindow.ShowDialog();
MessageBox.Show(otherWindow.GetData());
}
}
}
Code for getting the data just before closing the window:
using System.Windows;
namespace GetDataFromOtherWindow
{
public partial class MainWindow : Window
{
private Window1? otherWindow;
public MainWindow()
{
InitializeComponent();
}
protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
{
if (otherWindow != null)
{
MessageBox.Show(otherWindow.GetData());
}
base.OnClosing(e);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
otherWindow = new Window1();
otherWindow.Show();
}
}
}
I'm a WPF beginner and it's kind of hard to wrap my head around so many new concepts so fast (I have a deadline for this project, it is homework), including the MVVM design pattern.
So I need to create an app similar to Notepad++.
Each file should be opened in a new tab. I thought I might use an UserControl for that. (I've looked into it, and it seems a good choice)
The problem is that I don't know how to load the data from a file.
Here's my code:
MainWindow.xaml
<Window x:Class="WpfApp1.MainWindow"
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:local="clr-namespace:WpfApp1.ViewModel"
mc:Ignorable="d"
Title="Notepad-- - Octavian Niculescu" Height="450" Width="800">
<Window.DataContext>
<local:MainCommands/>
</Window.DataContext>
<Grid>
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="_File">
<MenuItem Header="_New" />
<MenuItem Header="_Open"
Command="{Binding Path=OpenFile}"/>
<MenuItem Header="_Save" />
<MenuItem Header="_Save as" />
<Separator />
<MenuItem Header="_Exit" />
</MenuItem>
<MenuItem Header="_Search">
<MenuItem Header="_Find" />
<MenuItem Header="_Replace" />
<MenuItem Header="_Replace all" />
<Separator />
<MenuItem Header="_Exit" />
</MenuItem>
<MenuItem Header="_Help">
<MenuItem Header="_About" />
<Separator />
<MenuItem Header="_Exit" />
</MenuItem>
</Menu>
<Menu DockPanel.Dock="Top"/>
</DockPanel>
</Grid>
</Window>
FileTab.xaml
<UserControl x:Class="WpfApp1.view.FileTab"
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:local="clr-namespace:WpfApp1.view"
mc:Ignorable="d"
d:DesignHeight="420" d:DesignWidth="800">
<Grid>
<TextBox AcceptsReturn="True" Name="FileContent"/>
<TextBlock HorizontalAlignment="Left" Margin="29,11,0,0" Text="FileName.txt" TextWrapping="Wrap" VerticalAlignment="Top"/>
</Grid>
</UserControl>
MainCommands.cs (where I have the ICommands for the buttons)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Windows.Input;
using WpfApp1.ViewModel;
using WpfApp1.auxiliar;
namespace WpfApp1.ViewModel
{
class MainCommands : INotifyPropertyChanged
{
private ICommand _openFile;
public ICommand OpenFile
{
get
{
if (_openFile == null)
{
_openFile = new RelayCommand(Commands.OpenFileFunc);
}
return _openFile;
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
and Commands.cs where I have the function for opening a file
using System;
using System.Collections.Generic;
using System.Text;
using WpfApp1.view;
namespace WpfApp1.auxiliar
{
static class Commands
{
public static void OpenFileFunc(object parameter)
{
Microsoft.Win32.OpenFileDialog openFileDlg = new Microsoft.Win32.OpenFileDialog();
Nullable<bool> result = openFileDlg.ShowDialog();
if (result == true)
{
user control textblock = openFileDlg.FileName;
user control textbox = System.IO.File.ReadAllText(openFileDlg.FileName);
}
}
}
}
The dialog opens. It works fine. But now I have to bind "user control textblock" and "user control textbox" to the data, and I don't know how to do it. I don't want (and I'm also not allowed) to use code behind.
Here's my folder structure, if it matters.
My question is how do I populate those two fields from the FileTab user control with the data from that if block from Commands.cs?
Thanks.
You should have some view models in your viewmodel folder something like a MainWindowViewModel and a FileTabViewModel. Those view models should have properties that the respective views bind to. One way to approach this would be
FileTabVM:
namespace WpfApp1.ViewModel
{
class FileTabViewModel : INotifyPropertyChanged
{
...
public string FileContent { ... }
public string FileName { ... }
...
}
}
MainWindowVM:
namespace WpfApp1.ViewModel
{
class MainWindowViewModel : INotifyPropertyChanged
{
...
public ObservableCollection<FileTabViewModel> FileTabs { ... }
...
}
}
Then put your open command logic in the MainWindowVM, then use that to create an instance of a FileTabVM with the data it needs.
Here's a good blog post if you need a more detailed guide.
I created a treeview following a youtube video and then made a datagrid that show some files from a chosen tar.gz file. Both of them use DataContext to show themselves on the program. The problem is that the TreeView disappear when the DataGrid is showing. I guess the problem is that both can't use DataContext like I'm using but I don't know a solution for it.
XAML Code
<Window x:Class="RFAnalyzerMain.MainWindow"
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:local="clr-namespace:RFAnalyzerMain"
mc:Ignorable="d"
Title="MainWindow"
Height="600" Width="900"
MinHeight="400" MinWidth="750"
Closing="Window_Closing" Loaded="Window_Loaded">
<Border Padding="2">
<Grid>
<!-- #region Grid Definitions -->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="10*" />
<ColumnDefinition Width="15" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="20" />
<RowDefinition Height="20" />
<RowDefinition Height="25*" />
<RowDefinition Height="20" />
</Grid.RowDefinitions>
<!--#endregion-->
<DockPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3">
<Menu DockPanel.Dock="Top">
<MenuItem Header="_File">
<MenuItem Header="Choose File to Read" x:Name="ChosenFile" Click="ChosenFile_Click" />
</MenuItem>
</Menu>
</DockPanel>
<Border Grid.Row="2" Padding="5 0" BorderThickness="0" BorderBrush="Gray">
<Grid>
<!-- Grid Definitions -->
<Grid.RowDefinitions>
<RowDefinition Height="25" />
<RowDefinition Height="*" />
<RowDefinition Height="20" />
</Grid.RowDefinitions>
<TextBlock Text="Folder" FontWeight="Bold" FontSize="18" Grid.Row="0"
VerticalAlignment="Center" HorizontalAlignment="Left" />
<!-- A TreeView of Fodlers -->
<Grid Grid.Row="1" Margin="0 0 0 5">
<TreeView x:Name="FolderView" ItemsSource="{Binding Items}" FontSize="10">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
</Style>
</TreeView.ItemContainerStyle>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal">
<Image Width="15" Margin="3"
Source="{Binding Type,
Converter={x:Static local:HeaderToImageConverter.Instance}}" />
<TextBlock VerticalAlignment="Center" Text="{Binding Name}" />
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>
<Button Content="Read" Grid.Row="2" Margin="0 0 0 0" Width="60" />
</Grid>
</Border>
<DataGrid Grid.Row="2" Grid.Column="1" ItemsSource="{Binding FileProperties}" />
<Button Grid.Column="2" Grid.Row="2">
<Image Source="Images/Button Left Arrow.png" Width="10" />
</Button>
</Grid>
</Border>
</Window>
Behind-Code
using System.IO;
using System.Windows;
namespace RFAnalyzerMain
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
#region Constructor
/// <summary>
/// Default Constructor
/// </summary>
public MainWindow()
{
InitializeComponent();
// Treeview
DataContext = new DirectoryStructureViewModel();
}
#endregion
#region User Events
/// <summary>
/// Choose a file from the explorer
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ChosenFile_Click(object sender, RoutedEventArgs e)
{
ExplorerHandler.OpenExplorer();
// Writes out all the files inside the file opened in the explorer
DataContext = new FilePropertiesViewModel();
}
#endregion
#region Starting Program
private void Window_Loaded(object sender, RoutedEventArgs e)
{
if (FilePaths.GZipDirectory.Exists == true)
Remove.FilesAndFolders();
}
#endregion
#region Closing Program
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
Remove.FilesAndFolders();
}
#endregion
}
}
If you need to see more code just ask and I'll edit the post and add the code asked for.
Since you implemented your logic in the code-behind, why don't you simply set the DataContext of the DataGrid in the event handler?:
private void ChosenFile_Click(object sender, RoutedEventArgs e)
{
ExplorerHandler.OpenExplorer();
// Writes out all the files inside the file opened in the explorer
dataGrid.DataContext = new FilePropertiesViewModel();
}
XAML:
<DataGrid x:Name="dataGrid" Grid.Row="2" Grid.Column="1" ItemsSource="{Binding FileProperties}" />
Then the TreeView won't disappear when you click on the button.
The other option would be to use a shared view model as suggested by #Sinatr but this will require some refactoring from what you currently have.
Typically you have to set DataContext once:
public MainWindow()
{
InitializeComponent();
DataContext = new MainWindowViewModel();
}
View model can have multiple properties:
public class MainWindowViewModel: INotifyPropertyChanaged
{
public DirectoryStructureViewModel Files { get; } = new DirectoryStructureViewModel();
FilePropertiesViewModel _selectedFile;
public FilePropertiesViewModel SelectedFile
{
get => _selectedFile;
set
{
_selectedFile = value;
OnPropertyChanged();
OnPropertyChanged(nameof(IsSelectedFileVisible));
}
}
public bool IsSelectedFileVisible => SelectedFile != null;
}
To which you can bind in the view:
<TreeView ItemsSource="{Binding Files.Items}"
SelectedItemChanged="TreeView_OnSelectedItemChanged" ... />
<DataGrid ItemsSource="{Binding SelectedFile.FileProperties}"
Visibility="{Binding IsSelectedFileVisible, Converter={StaticResource BoolToVis}}" ... />
And
void TreeView_OnSelectedItemChanged(...)
{
var vm = (MainWindowViewModel)DataContext;
vm.SelectedFile = ...
}
References: 1, 2, 3.
It seems to be straightforward to get the Version Number e.g.
string ver Assembly.GetExecutingAssembly().GetName().Version.ToString();
And displaying that string in an "About..." menu item should also be. But Google results all seem complex e.g.
https://stackoverflow.com/questions/2849265/how-to-pass-data-when-using-menuitem-itemcontainerstyle
https://stackoverflow.com/questions/21585828/menuitem-passing-selected-item-to-viewmodel-via-relaycommand-ala-mvvm-light-he
There must be a simple way to do this. Something along the lines of
Window x:Class="WpfApp1.MainWindow"
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:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Menu>
<MenuItem Header="File">
<MenuItem Header="Open"/>
<MenuItem Header="Close"/>
</MenuItem>
<MenuItem Header="About">
<MenuItem Header="Version"/>
</MenuItem>
<Grid>
</Grid>
</Menu>
</Window>
where the last header becomes "Version" + ver.
Or moving into the more complex
How do I dynamically bind and statically add MenuItems?
public partial class MainWindow : Window
{
private ObservableCollection<MyObject> _windows = new ObservableCollection<MyObject>();
public MainWindow()
{
InitializeComponent();
Windows.Add(new MyObject { Title = "Collection Item 1" });
Windows.Add(new MyObject { Title = "Collection Item 2" });
}
public ObservableCollection<MyObject> Windows
{
get { return _windows; }
set { _windows = value; }
}
}
public class MyObject
{
public string Title { get; set; }
}
<Window x:Class="WpfApplication8.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="233" Width="143" Name="UI">
<Window.Resources>
<CollectionViewSource Source="{Binding ElementName=UI, Path=Windows}" x:Key="YourMenuItems"/>
</Window.Resources>
<Grid DataContext="{Binding ElementName=UI}">
<Menu Height="24" VerticalAlignment="Top">
<MenuItem Header="_View" >
<MenuItem Header="Windows">
<MenuItem.ItemsSource>
<CompositeCollection>
<CollectionContainer Collection="{Binding Source={StaticResource YourMenuItems}}" />
<MenuItem Header="Menu Item 1" />
<MenuItem Header="Menu Item 2" />
<MenuItem Header="Menu Item 3" />
</CompositeCollection>
</MenuItem.ItemsSource>
<MenuItem.ItemContainerStyle>
<Style>
<Setter Property="MenuItem.Header" Value="{Binding Title}"/>
</Style>
</MenuItem.ItemContainerStyle>
</MenuItem>
</MenuItem>
</Menu>
</Grid>
(which doesn't display "Collection Item 1" etc for me)
Just for the record, here's an MWE which does the very simple thing I wanted.
using System.Collections.ObjectModel;
using System.Reflection;
using System.Windows;
namespace WpfApp2
{
public partial class MainWindow : Window
{
public ObservableCollection<MyMenuItem> _windows = new ObservableCollection<MyMenuItem>();
public MainWindow()
{
InitializeComponent();
string ver = Assembly.GetExecutingAssembly().GetName().Version.ToString();
MyMenuItem versionMenuItem = new MyMenuItem { Title = "Version " + ver };
Windows.Add(versionMenuItem);
}
public ObservableCollection<MyMenuItem> Windows
{
get { return _windows; }
set { _windows = value; }
}
}
public class MyMenuItem
{
public string Title { get; set; }
}
}
<Window x:Class="WpfApp2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp2"
Title="MainWindow" Height="233" Width="143" Name="UI">
<Window.Resources>
<CollectionViewSource Source="{Binding ElementName=UI, Path=Windows, FallbackValue=versionMenuItem, TargetNullValue=0}" x:Key="MyMenuItems" />
</Window.Resources>
<Grid DataContext="{Binding ElementName=UI}">
<Menu Height="24" VerticalAlignment="Top">
<MenuItem Header="_Version" >
<MenuItem Header="About">
<MenuItem.ItemsSource>
<CompositeCollection>
<CollectionContainer Collection="{Binding Source={StaticResource MyMenuItems}}" />
<MenuItem Header="Licensed To" />
</CompositeCollection>
</MenuItem.ItemsSource >
<MenuItem.ItemContainerStyle>
<Style>
<Setter Property="MenuItem.Header" Value="{Binding Title}" />
</Style>
</MenuItem.ItemContainerStyle>
</MenuItem>
</MenuItem>
</Menu>
</Grid>
</Window>
<Application x:Class="WpfApp2.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp2"
StartupUri="MainWindow.xaml">
<Application.Resources>
<Style TargetType="MenuItem">
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
</Style>
</Application.Resources>
</Application>
Setting the FallbackValue to versionMenuItem to eliminate one of the Data issues.
<CollectionViewSource Source="{Binding ElementName=UI, Path=Windows, FallbackValue=versionMenuItem, TargetNullValue=0}" x:Key="MyMenuItems" />
I have a ContextMenu attached to a ListBox who offer two options : create and delete element. I want to hide only the "Delete" element if the ListBox data is empty.
I've tried to bind the property "Visibility" with a variable in the view's code setting it to "Collapsed" or "Visible", but it didn't work.
XAML :
<ListBox ItemsSource="{Binding ElementList}"
SelectedItem="{Binding SelectedElement}"
SelectionChanged="ListBoxProjects_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Name}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem Name="Add" Click="Add_Click" Header="Add element" />
<MenuItem Name="Delete" Click="Delete_Click"
HeaderStringFormat="Delete element {0}"
Header="{Binding SelectedElement.Name}"
Visibility="{Binding ElementContextMenuVisibility}" />
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>
CS :
public partial class View : UserControl
{
private ViewModel _viewModel = ViewModel.Instance;
private Visibility _elementContextMenuVisibility { get; set; }
public Visibility ElementContextMenuVisibility
{
get { return _elementContextMenuVisibility; }
set { _elementContextMenuVisibility = value; }
}
public View()
{
InitializeComponent();
}
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (_viewModel.ElementList != null && _viewModel.ElementList.Count > 0)
ElementContextMenuVisibility = Visibility.Visible;
else
ElementContextMenuVisibility = Visibility.Collapsed;
}
}
Thanks
You can achieve this with RelativeSource binding and no need of xaml.cs code.
XAML
<ListBox ItemsSource="{Binding ElementList}"
SelectedItem="{Binding SelectedElement}">
<ListBox.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
</ListBox.Resources>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Name}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem Name="Add" Click="Add_Click" Header="Add element" />
<MenuItem Name="Delete" Click="Delete_Click"
HeaderStringFormat="Delete element {0}"
Header="{Binding SelectedElement.Name}"
Visibility="{Binding PlacementTarget.HasItems, RelativeSource={RelativeSource AncestorType=ContextMenu}, Converter={StaticResource BooleanToVisibilityConverter}}" />
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>