I created next WPF controls : Window1, View, Edit in different files:
In MainWindow.xaml MainWindow contein two ContentControls
<Grid>
<ContentControl x:Name="Viewer" Content="ContentControl1" DockPanel.Dock="Top" Height="Auto" RenderTransformOrigin="0.5,0.5">
</ContentControl>
<ContentControl x:Name="Editor" Content="ContentControl2" DockPanel.Dock="Top" Height="Auto" VerticalAlignment="Bottom" RenderTransformOrigin="0.5,0.5" Visibility="Hidden"/>
</Grid>
This is part of .cs file:
public partial class MainWindow : Window
{
View v = new View();
Edit e = new Edit();
public MainWindow()
{
InitializeComponent();
Window1.Viewer.Content = v;
Window1.Editor.Content = e;
}
public void swichToEditor()
{
Window1.Editor.Visibility = System.Windows.Visibility.Visible;
Window1.Viewer.Visibility = System.Windows.Visibility.Hidden;
}
public void swichToViewer()
{
Window1.Ediort.Visibility = System.Windows.Visibility.Hidden;
Window1.Viewer.Visibility = System.Windows.Visibility.Visible;
}
}
ComtentControl1 with x:name=Editor contain this userControl:
public partial class Edit : UserControl
{
public Edit()
{
this.InitializeComponent();
}
private void Button1_Click(object sender, System.Windows.RoutedEventArgs e)
{
// TODO: Add event handler implementation here.
}
}
ComtentControl2 with x:name=Viewer contain this userControl:
public partial class View : UserControl
{
public View()
{
this.InitializeComponent();
}
private void Button2_Click(object sender, System.Windows.RoutedEventArgs e)
{
// TODO: Add event handler implementation here.
}
}
When button1 will be pressed i need that Editor will be hide and Viewer will be visible. and vice-versa
I know better c++ syntax. and signal-slot method closer to me :)
What your advice to me?
You can use the RoutedEvent's behavior. You just need to register your Window to the Click RoutedEvent. Take a look:
public partial class MainWindow : Window
{
View v = new View();
Edit e = new Edit();
public MainWindow()
{
InitializeComponent();
Window1.Viewer.Content = v;
Window1.Editor.Content = e;
EventManager.RegisterClassHandler(GetType(), Button.ClickEvent, new RoutedEventHandler(OnButtonClick));
}
private void OnButtonClick(object sender, RoutedEventArgs e)
{
if (e.Source is View)
{
SwichToEditor();
}
else
{
SwichToViewer();
}
}
public void SwichToEditor()
{
Window1.Editor.Visibility = System.Windows.Visibility.Visible;
Window1.Viewer.Visibility = System.Windows.Visibility.Hidden;
}
public void SwichToViewer()
{
Window1.Ediort.Visibility = System.Windows.Visibility.Hidden;
Window1.Viewer.Visibility = System.Windows.Visibility.Visible;
}
}
Then you do not need to have a button click event handler in your UserControls.
I hope this sample can help you.
Related
once to explain, I open a xaml page via "frame.content" and in this page I have opened, I want to open another one but on the frame where the second page is running.
but i can't open the page,
nothing happens. not even an expection.
So here what I have written:
This is the class from the page that is open
private void bttn_start(object sender, RoutedEventArgs e)
{
MainWindow mw = new MainWindow();
mw.JoinNextPage();
}
This is the MainWindow class where the frame is.
public partial class MainWindow : Window
{
public void JoinNextPage() => pageMirror.Content = new page_finish();
}
You should use RoutedCommand to trigger the Frame navigation instead of the static MainWindow reference.
This removes the complete navigation logic (button event handlers) from your pages.
MainWindow.xaml.cs
public partial class MainWindow : Window
{
public static RoutedCommand NextPageCommand { get; } = new RoutedCommand("NextPageCommand", typeof(MainWindow));
public MainWindow()
{
InitializeComponent();
CommandBindings.Add(
new CommandBinding(NextPageCommand, ExecuteNextPageCommand, CanExecuteNextPageCommand));
}
private void CanExecuteNextPageCommand(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
private void ExecuteNextPageCommand(object sender, ExecutedRoutedEventArgs e)
{
// Logic to select the next Frame content
JoinNextPage();
}
}
MainWindow.xaml
<Window>
<Frame>
<Frame.Content>
<Page>
<Button Command="{x:Static local:MainWindow.NextPageCommand}"
Content="Next Page" />
</Page>
</Frame.Content>
</Frame>
</Window>
Try this:
private void bttn_start(object sender, RoutedEventArgs e)
{
MainWindow mw = (MainWindow)Application.Current.MainWindow;
mw.JoinNextPage();
}
<Window x:Class="WpfApp12.MainWindow"
xmlns=...usual namespaces...
Loaded="Window_Loaded"
>
<Window.Resources>
<DataTemplate x:Key="myHeaderTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{TemplateBinding Content}"/>
<Button Margin="5,0,0,0" x:Name="MyButton">Press me</Button>
</StackPanel>
</DataTemplate>
</Window.Resources>
<!-- Just point the datacontext to the code behind -->
<Window.DataContext>
<Binding RelativeSource="{RelativeSource Mode=Self}"/>
</Window.DataContext>
<DataGrid Name="DG" ItemsSource="{Binding People}"/>
</Window>
This, togheter with the code behind below gives just what I want: a DataGrid with a column whose header has been dynamically assigned a DataTemplate with a Button "Press me":
The code behind:
public partial class MainWindow : Window
{
public class Person
{
public string Name { get; set; }
public string Surname { get; set; }
}
public MainWindow()
{
People.Add(new Person() { Name = "Isaac", Surname = "Newton" });
People.Add(new Person() { Name = "Galileo", Surname = "Galilei" });
InitializeComponent();
}
public ObservableCollection<Person> People { get; } = new ObservableCollection<Person>();
private void Window_Loaded(object sender, RoutedEventArgs e)
{
DG.Columns[0].HeaderTemplate = (DataTemplate)FindResource("myHeaderTemplate");
//how to access the button in the template in order to assign the click event?
}
private void MyButton_Click(object sender, RoutedEventArgs e)
{
//DO SOMETHING
}
}
}
Now i want to dynamically wire MyButton_Click event to the button in the template.
This kind of problems seem to have a lot of coverage, this one being one of the best:
WPF How to access control from DataTemplate
There there is something like:
ComboBox myCombo = _contentPresenter.ContentTemplate.FindName("myCombo", _contentPresenter) as ComboBox;
I'm not very familiar with the templating, and I cannot find the starting point, the "content presenter" on which to call the FindName.
You could use a recursive helper method that finds the Button in the visual tree:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
DG.Columns[0].HeaderTemplate = (DataTemplate)FindResource("myHeaderTemplate");
DG.Dispatcher.BeginInvoke(new Action(() =>
{
DataGridColumnHeadersPresenter presenter = FindVisualChild<DataGridColumnHeadersPresenter>(DG);
DataGridCellsPanel dataGridCellsPanel = FindVisualChild<DataGridCellsPanel>(presenter);
DataGridColumnHeader header = dataGridCellsPanel.Children[0] as DataGridColumnHeader;
Button button = FindVisualChild<Button>(header);
if (button != null)
button.Click += MyButton_Click;
}));
}
private void MyButton_Click(object sender, RoutedEventArgs e)
{
//DO SOMETHING
}
private static T FindVisualChild<T>(DependencyObject obj) where T : DependencyObject
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
if (child != null && child is T)
return (T)child;
else
{
T childOfChild = FindVisualChild<T>(child);
if (childOfChild != null)
return childOfChild;
}
}
return null;
}
I've created WPF application with NotifyIcon to work in tray.
public partial class MainWindow : Window
{
public NotifyIcon NotifyIcon { get; } = new NotifyIcon
{
Icon = Properties.Resources.status_on_ico,
Visible = true
};
public MainWindow()
{
InitializeComponent();
NotifyIcon.ContextMenuStrip = MyContextMenuStrip;
NotifyIcon.Click += NotifyIcon_Click;
}
private void Window_Closing(object sender, CancelEventArgs e)
{
e.Cancel = true;
WindowState = WindowState.Minimized;
}
private void NotifyIcon_Click(object sender, EventArgs e)
{
Show();
}
}
XAML of main window is nothing special and not relevant.
I want to create ContextMenuStrip of NotifyIcon in XAML (I know how to do it code behind but don't want it).
Here is what I've managed.
<WindowsFormsHost>
<wf:ContextMenuStrip x:Name="MyContextMenuStrip" TopLevel="False">
<wf:ContextMenuStrip.Items>
<!-- How to add items here? -->
</wf:ContextMenuStrip.Items>
</wf:ContextMenuStrip>
</WindowsFormsHost>
The question is how to add items to ContextMenuStrip.Items with Name and Click event handlers in XAML?
The question is how to add items to ContextMenuStrip.Items with Name and Click event handlers in XAML?
Try this:
<WindowsFormsHost>
<wf:ContextMenuStrip x:Name="MyContextMenuStrip" TopLevel="False">
<wf:ContextMenuStrip.Items>
<wf:ToolStripMenuItem Text="test1" Click="It_Click" />
<wf:ToolStripMenuItem Text="test2" />
</wf:ContextMenuStrip.Items>
</wf:ContextMenuStrip>
</WindowsFormsHost>
private void It_Click(object sender, EventArgs e)
{
MessageBox.Show("click!");
}
I'm developing my first application in WPF with the pattern MVC and I have a question.
I have created a usercontrol from type Grid to made a custom title bar. This grid contains a X button and I want to associate this button to a command.
My grid in XAML:
<Grid x:Class="Views.TitleBarView"
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"
mc:Ignorable="d"
Style="{DynamicResource TitleStyleGrid}"
x:Name="barView">
<Label x:Name="labelAppName" Style="{DynamicResource TitleStyleLabel}" Content="Title"/>
<Button x:Name="bttnClose" Style="{DynamicResource ButtonStyleCloseWindow}" Command="{Binding CloseCommand}"/>
<Button x:Name="buttonMinimize" Style="{DynamicResource ButtonStyleMinimizeWindow}" Command="{Binding MinimizeCommand}"/>
</Grid>
The C# view:
public partial class TitleBarView : Grid
{
public TitleBarView()
{
InitializeComponent();
TitleBarViewModel tvm = new TitleBarViewModel();
tvm.RequestClose += (s, e) => this.Close();
tvm.RequestMinimize+= (s, e) => this.Minimize();
DataContext = tvm;
}
private void Close()
{
Window.GetWindow(this).Close();
}
private void Minimize()
{
Application.Current.MainWindow.WindowState = System.Windows.WindowState.Minimized;
}
}
The C# viewModel:
public class TitleBarViewModel : ViewModelBase, IRequestMinimizeViewModel, IRequestCloseViewModel
{
private RelayCommand minimizeCommand;
protected RelayCommand closeCommand;
public event EventHandler RequestMinimize;
public event EventHandler RequestClose;
#region MinimizeCommand
public ICommand MinimizeCommand
{
get
{
if (minimizeCommand == null)
{
minimizeCommand = new RelayCommand(Minimize);
}
return minimizeCommand;
}
}
private void Minimize()
{
RequestMinimize(this, null);
}
#endregion
#region CloseCommand
public ICommand CloseCommand
{
get
{
if (closeCommand == null)
{
closeCommand = new RelayCommand(Close);
}
return closeCommand;
}
}
protected void Close()
{
RequestClose(this, null);
}
#endregion
}
I saw that it's not recommended to set a DataContext on a userControl. And when I do this, I can't change the close command. For example I want that when the main windows calls command close it calls Application.Current.Shutdown(); instead of Application.Current.Shutdown();
I know that I have something wrong but I'm too confuse to solve it. Can you explain me how to create command for userControl ? (Or just tell me what I'm doing wrong)
Thank you
I have a problem and nothing come to my mind how to solve this.
I need to add a button to Favorites in a StackPanel, the problem is that the button is pressed on other page that is StackPanel declared and I can't Add button to it's Children.
So, I have 2 pages: MainPage.xaml and PlayerPage.xaml .
In MainPage I keep a StackPanel with Buttons like:
<StackPanel x:Name="mainStack" >
<Button x:Name="but1" Click="Button2_Click" Tag="/videos/video1.mp4" Content="Play Video 1" />
<Button x:Name="but2" Click="Button2_Click" Tag="/videos/video2.mp4" Content="Play Video 2" />
<Button x:Name="but3" Click="Button2_Click" Tag="/videos/video3.mp4" Content="Play Video 3" />
</StackPanel>
<StackPanel x:Name="favoriteStack" >
<!-- Here need to be added favorite videos when user press Add to fav button! -->
</StackPanel>
.cs
private void Button2_Click(object sender, EventArgs e)
{
NavigationService.Navigate(
new Uri("/PlayerPage.xaml?path=" +
HttpUtility.UrlEncode((sender as Button).Tag.ToString()),
UriKind.Relative));
}
In PlayerPage.xaml :
<MediaElement x:Name="mediaElement1"
MediaOpened="mediaElement1_MediaOpened"
MediaFailed="mediaElement1_MediaFailed"
MediaEnded="mediaElement1_MediaEnded"
CurrentStateChanged="mediaElement1_CurrentStateChanged" />
<Button x:Name="AddToFav" Click="Button1_Click"
Content="Add this video to Favorites" />
.cs
protected override void OnNavigatedTo(NavigationEventArgs e)
{
if (NavigationContext.QueryString.TryGetValue("path", out path))
{
if (!string.IsNullOrWhiteSpace(path))
{
mediaElement1.Source = new Uri( path );
}
}
}
private void Button1_Click(object sender, RoutedEventArgs e)
{
// here must be somethink like:
Button butsender = new Button();
butsender = sender as Button;
stack2.Children.Add(butsender);
//better will be to save to Isolated Storage or somethink like this for future launching...
}
I have a lot of problems because I don't really get it how to perform that... I've tried to use global App Bar and allot more but unsuccesfully. Any help would be appreciated! Thanks!
The best way to do this is to follow the MVVM Pattern. You'll have a ViewModel class defined containing two lists.
public class MainViewModel : INotifyPropertyChanged
{
public ObservableCollection<Video> Videos { get; set; }
public ObservableCollection<Video> FavoriteVideos { get; set; }
public MainViewModel()
{
Videos = new ObservableCollection<Video>();
FavoriteVideos = new ObservableCollection<Video>();
}
private Video selectedVideo;
public Video SelectedVideo
{
get { return selectedVideo; }
set { selectedVideo = value; NotifyPropertyChanged("SelectedVideo"); }
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
In App.xaml.cs you'll define the ViewModel
private static MainViewModel viewModel = null;
public static MainViewModel ViewModel
{
get
{
// Delay creation of the view model until necessary
if (viewModel == null)
viewModel = new MainViewModel();
return viewModel;
}
}
Then you can set the data context of both pages (MainPage and ther other) in the constructor like this:
DataContext = App.ViewModel;
Now you'll only have to bind the items to both lists (StackPanel won't do here. Use other listing like ListBox)
ItemsSource="{Binding Videos}"
ItemsSource="{Biding FavoriteVideos}"
For the navigation if you use ListBox just set the click event
ItemClick="ItemClick"
private void ItemClick(object sender, ItemClickEventArgs e)
{
Video item = e.ClickedItem as Video;
App.ViewModel.SelectedVideo = item;
NavigationService.Navigate(new Uri("/PlayerPage.xaml,UriKind.Relative));
}
At the PlayerPage just bind to SelectedVideo and you're good. For favorite you just have to add the video to the FavoriteList
private void FavoriteButton_Click(object sender, RoutedEventArgs e)
{
if(!App.ViewModel.FavoriteVideos.Contains(App.ViewModel.SelectedVideo)) {
App.ViewModel.FavoriteVideos.Add(App.ViewModel.SelectedVideo);
}
}
Now you can dynamically add data in your app if needed. StackPanel will only help with your static videos and it's not practical to use if the data changes.