Closing a UserControl in a Grid of MainWindow - c#

I am trying to close a usercontrol with a button click.
The usercontrol is in a grid of the mainwindow.
This is how i open it and it works.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
UsLogin _UsLogin = new UsLogin();
OpenUserControl(_UsLogin);
}
private void OpenUserControl(UsLogin _UsLogin)
{
grdVensters.Children.Add(_UsLogin);
}
}
Now in the usercontrol i have a button to confirm the login.
(no code yet this just a mockup to show in class how i want it to look)
I want this button to close this usercontrol in grdVensters so I have my main window ready.
I can't seem to access grdVensters in my usercontrol. Can i make a link?
tried: Close current UserControl
but best answer closes MainWindow what i don't want.
This looks like what i need but can't make it work in my case. Causing a UserControl to remove itself (WPF)
Thanks in advance!

You should really go for MVVM if you want to work with WPF. There are tons of resources on the web. However, I've created a small example that should lead you to the right direction. You can show/hide the login view by setting the correlating property on the ViewModel. The BooleanToVisibilityConverter converts the bool value to a Visibility value. I also added a CheckBox to demonstrate a simple example how you could change the visible state.
XAML
<StackPanel>
<StackPanel.Resources>
<BooleanToVisibilityConverter x:Key="bToV" />
</StackPanel.Resources>
<CheckBox IsChecked="{Binding Path=IsLoginVisible, UpdateSourceTrigger=PropertyChanged}" />
<Button Content="Login"
Visibility="{Binding Path=IsLoginVisible, Converter={StaticResource bToV}}" />
<!--<yournamespace:UsLogin Visibility="{Binding Path=IsLoginVisible, Converter={StaticResource bToV}}/>-->
</StackPanel>
Code Behind
public partial class MainWindow
{
public MainWindow()
{
this.InitializeComponent();
DataContext = new MainViewModel();
}
}
public class MainViewModel : ViewModelBase
{
private bool _isLoginVisible;
public bool IsLoginVisible
{
get
{
return _isLoginVisible;
}
set
{
_isLoginVisible = value;
OnPropertyChanged();
}
}
}

Related

Linking button controls to data (WPF)

I am working on an application showing 20 graphic buttons controls in a MainWindow (Button1 to Button20).
Each button control can display a Content string, and has a tooltip designed as follow :
<Button x:Name="button1" FontWeight="Bold" FontSize="15" Content="" HorizontalAlignment="Left" Margin="20,69,0,0" VerticalAlignment="Top" Width="92" Height="29" Click="Button_Click" Background="#FFFFFFFF" MouseEnter="button_MouseEnter">
<Button.ToolTip>
<Border Margin="-4,0,-4,-3" Padding="10" Background="Yellow">
<Border.BitmapEffect>
<OuterGlowBitmapEffect></OuterGlowBitmapEffect>
</Border.BitmapEffect>
<Label x:Name ="lbl1" FontSize="20" Content="{Binding Path=ToolTip}">
</Label>
</Border>
</Button.ToolTip>
<Button.Effect>
<DropShadowEffect/>
</Button.Effect>
</Button>
I would like to define the string content and the tooltip string for each button in an XML file so this information can be changed by modifying the XML file.
For this, I created a ViewModel defining an object called Bouton (in french) :
public class Bouton : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
void Notify(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
int boutonNumber;
public int BoutonNumber{ get { return boutonNumber; } set { boutonNumber= value; Notify("BoutonNumber"); } }
string texteBouton;
public string TexteBouton { get { return texteBouton; } set { texteBouton = value; Notify("TexteBouton"); } }
string tooltip;
public string Tooltip { get { return tooltip; } set { tooltip = value; Notify("ToolTip"); } }
public Bouton(int nb, string tb, string tt)
{
BoutonNumber = nb;
TexteBouton = tb;
Tooltip = tt;
}
}
When reading the XML file, I create 20 objects of Bouton type with the information about boutonNumber, Content and Tooltip. Then all these Bouton objects are stored into a List collection.
Now I want to use DataBinding between my Bouton list and the graphic controls on my MainWindow to be able to display the content string and the tooltip string on each button.
In the MainWindow, I used the following code :
public MainWindow()
{
InitializeComponent();
List<Bouton> lst = Utilities.CreateList();
this.DataContext = lst;
}
where lst is a List collection correctly initialized.
But I do not know how to make the databinding work on the Button controls. How can I make each of the 20 Button controls correctly link to the corresponding Bouton object (contained in the Boutons collection) ? I mean how can Button1 control get its strings from my Bouton1 object, the Button2 control get its string from Bouton2 object and so on until Button20 control and Bouton20 object ?
Thank you for your help. Please note I am a beginner with WPF and this is my first WPF project with Visual Studio.
I think the simplest option would be to wrap your button in a UserControl.
This UserControl then contains a property of type Bouton (not great naming btw. - even if it is a different language, the term "button" already exists, so this is rather ambiguous. As a non-native english speaker myself, I also recommend getting used to naming in English, it will save you lots of headaches in the long run, but that might be subjective )
You can then bind directly to that property in the UserControl's template. All you have to do is assign each UserControl the correct button data.
eg.
public class CustomButton : UserControl
{
public Bouton ParsedButtonData { get; set; }
public CustomButton()
{
DataContext = this;
InitializeComponent();
}
}
and in your UserControl's template:
<Button ...>
<Button.ToolTip>
<Border ...>
<Label Content="{Binding ParsedButtonData.Tooltip}" ...>
</Label>
</Border>
</Button.ToolTip>
</Button>
You can then place the UserControl in your XAML like this:
xmlns:ctrls="clr-namespace:MyProject.MyNamespace"
<ctrls:CustomButton name="myFirstButton"/>
Now all you have to do is make sure each CustomButton has their ParsedButtonData set to the corresponding piece of data. You can either set this manually for each button created in your XAML, or you can create the CustomButtons through C# in the first place.
If you create your UserControls in XAML, for example:
public void SomeMethod()
{
myFirstButton.ParsedButtonData = lst[0];
}
Alternatively, you might want to look into extending ItemsControl. It's basically made for this sort of application. An ItemsControl has an ItemsSource, which can be any collection type such as List<> or ObservableCollection<>. It then creates its children from that collection, setting the DataContext automatically to the corresponding element in said list.
Examples of that would be DataGrid or ListView. I find that to be a little more involved though, if you really just want to place a bunch of a Buttons on a single View.

Learning MVVM. Calling Methods

I'm currently learning how MVVM works and gettings a bit confused.
What I Have Now: I've got a MainWindow.xaml and have made a button that adds in UserControl1.xaml adding it to a ContentControl, which all works great. I've got a folder named ViewModels with a class named SettingsViewModel.cs and another folder named Views with a UserControl named SettingsView.xaml
What I'm trying to figure out: In the User Control I'll have things like buttons, checkboxes, and some other stuff, I want to be able to have a button press in the MainWindow to call a method where I can do stuff like changing the visibility of items among other things. How I go about calling this method from the MainWindow and where to put the method [SettingsViewModels.cs or SettingsView.xaml].
I'm still very new to programming so I'm probability leaving out a bunch of info, so ask me any question.
I have accually got this to work the other way around; calling a method in MainWindow from a UserControl like this...
//this is in the UserControl
private void Button1_Click(object sender, RoutedEventArgs e)
{
MainWindow callMethod = (MainWindow)Application.Current.MainWindow;
callMethod.MyMethod1();
}
//this is in the MainWindow
pubic void MyMethod1()
{
//whatevery i want here
}
There are a couple of things to consider. In MVVM, View communicate to ViewModel through bindings and ViewModel communicate to the View through events typical from INotifyPropertyChanged and ICollectionChanged. Buttons should be binded to a property of type ICommand. The ViewModel should not know about WPF control stuff like Visibility etc.
To change visibility you use an IValueConverter called BooleanToVisiblityConverter.
Without quite understanding what you are asking, here is some pseudo code of how I would do it.
The structure of your files doesn't matter, but dividing them into Views and ViewModels is a good idea.
Disclaimer: This code will not run, shows only the concept. I left Visual Studio on my other computer.
ViewModel:
public class MainWindowViewModel
{
public ICommand OpenCommand { get; }
public object Child { get; private set; }
public MainWindowViewModel()
{
OpenCommand = new RelayCommand(Open);
}
private void DoOpen()
{
Child = new ChildViewModel();
}
}
public class ChildViewModel
{
public bool ShowSomething { get; }
}
public class Program
{
private void SomeStartupLogic()
{
var window = new MainWindow();
windows.DataContext = new MainWindowViewModel(); // or use an IoC container
window.Show();
}
}
View
<Window class="MainWindow">
<Window.Resources>
<DataTemplate DataType="{x:Type ChildViewModel}">
<ChildView/>
</DataTemplate>
</Window.Resources>
<Grid>
<ContentControl Content="{Binding Child}"/>
<Button Command="{Binding OpenCommand}"/>
</Grid>
</Window>
<UserControl class="ChildView">
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConvert"/>
</UserControl.Resources>
<Grid>
<TextBlock Text="Something" Visibility="{Binding ShowSomething, Converter={StaticResource BooleanToVisibilityConvert}/>
</Grid>
</UserControl>
Links
MVVM
Commands
PropertyChanged

How can I bind a WPF checkbox's IsChecked property to a boolean property of an object that is not a window

I found a lot of examples on how to bind the IsChecked property of a WPF checkbox to a boolean property, if both belong to the same Window class. I want to do a different thing:
I have the main window (excerpt):
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
}
private readonly SoundFx _soundFx = new SoundFx();
private void _StartNewGame()
{
_soundFx.GameStarted();
}
}
Then I have the SoundFx class (excerpt):
public class SoundFx : DependencyObject
{
public void GameStarted()
{
if (Enabled)
{
_PlayGameStartedSound();
}
}
public bool Enabled
{
get { return (bool) GetValue(EnabledProperty); }
set { SetValue(EnabledProperty, value); }
}
public static readonly DependencyProperty EnabledProperty =
DependencyProperty.Register("Enabled", typeof(bool),
typeof(SoundFx), new UIPropertyMetadata(false));
}
And I have the XAML (excerpt):
<Grid>
<CheckBox IsChecked="{Binding ElementName=_soundFx, Path=Enabled}" x:Name="checkBoxSoundFx" Content="Sound FX" HorizontalAlignment="Right" Margin="0,0,10,10" VerticalAlignment="Bottom"/>
</Grid>
To be honest, I'm new to WPF and don't know exactly what I'm doing. What I'm trying to achieve is that the value of _soundFx.Enabled be changed when the user clicks on the checkBoxSoundFx element, without using any event handlers like Checked or Unchecked. This should be possible with data binding, shouldn't it?
First you need to create
public SoundFx _soundFx { get; set; }
as public property, because you cannot bind to private field
public MainWindow()
{
InitializeComponent();
_soundFx = new SoundFx();
}
And from xaml you need to bind like:
<CheckBox IsChecked=
"{Binding RelativeSource=
{RelativeSource Mode=FindAncestor,AncestorType=Window},
Path=_soundFx.Enabled}"}"
x:Name="checkBoxSoundFx"
Content="Sound FX"
HorizontalAlignment="Right"
Margin="0,0,10,10"
VerticalAlignment="Bottom"/>
You were close, you need a property to bind to and you need to set the DataContext if you didn't do it:
public partial class MainWindow
{
public MainWindow()
{
this.DataContext = this;
InitializeComponent();
}
private readonly SoundFx _soundFx = new SoundFx();
public SoundFx {get {return _soundFx;}}
private void _StartNewGame()
{
_soundFx.GameStarted();
}
}
You then need to bind to this property (and set the mode to OneWayToSource if you only need to set the property, never update the CheckBox according to the property value):
<Grid>
<CheckBox IsChecked="{Binding Path=SoundFx.Enabled, Mode=OneWayToSource}" x:Name="checkBoxSoundFx" Content="Sound FX" HorizontalAlignment="Right" Margin="0,0,10,10" VerticalAlignment="Bottom"/>
</Grid>
By the way I'm not sure why you SoundFx is a DependencyObject and why your Enabled property is a DependencyProperty. A simple property would work aswell in this particular example.
DependencyProperties are useful when you want to set them in a Style or animate them with a Storyboard for example, you don't seem to be in this case. I think SoundFx should inherit DependencyObject and Enabled should be a simple property (This is an opinion I make knowing very little about your project though).
As I've managed to grow more experienced in WPF in the meantime, I would now say that my question itself was wrong. In order to avoid confusion in binding and unnecessary dependencies between view and model, I would now always prefer MVVM for cases like this.
Example: https://codereview.stackexchange.com/questions/124361/mvvm-am-i-doing-it-right

How to bind the DataContext of the Window or its child to one specific property of the Window?

A bit silly question, but somehow I can't find how to bind the DataContext of the Window or its Content (e.g a Grid panel) to one specific property of the Window (say, ViewModel in my example below):
Code:
internal partial class MyWin : Window
{
public MyViewModelType ViewModel { get; set; }
...
}
XAML:
<Window x:Class="MyNs.MyWin"
...
DataContext="{Binding RelativeSource={RelativeSource Self}}" />
<Grid DataContext={Binding ViewModel}> <!-- doesn't work??? -->
...
</Grid>
</Window>
I think you have this the wrong way around
if your window does the hooking up, it will work okay
public partial class MyWindow
{
public MyWindow()
{
InitializeComponent();
DataContext = ViewModel = new MyViewModelType();
}
}
Please define field for the viewmodel as it is not changing and implement INPC
private MyViewModelType viewmodel;
public MyViewModelType ViewModel
{
get
{
if(viewmodel == null)
{
viewmodel = new MyViewModelType();
}
return viewmodel;
}
set
{
viewmodel = value;
OnPropertyChanged("ViewModel")
}
}
Rest of code remains the same.

WPF checkbox binding

While it is trivial to store a checkbox's checked state in a variable using the checkbox's Click event, how would I do it via databinding? All the examples I have found have the UI updated from some datasource, or bind one control to another; I want to update a member variable when the checkbox is clicked.
TIA for any pointers...
You must make your binding bidirectional :
<checkbox IsChecked="{Binding Path=MyProperty, Mode=TwoWay}"/>
You need a dependency property for this:
public BindingList<User> Users
{
get { return (BindingList<User>)GetValue(UsersProperty); }
set { SetValue(UsersProperty, value); }
}
public static readonly DependencyProperty UsersProperty =
DependencyProperty.Register("Users", typeof(BindingList<User>),
typeof(OptionsDialog));
Once that is done, you bind the checkbox to the dependency property:
<CheckBox x:Name="myCheckBox"
IsChecked="{Binding ElementName=window1, Path=CheckBoxIsChecked}" />
For that to work you have to name your Window or UserControl in its openning tag, and use that name in the ElementName parameter.
With this code, whenever you change the property on the code side, you will change the textbox. Also, whenever you check/uncheck the textbox, the Dependency Property will change too.
EDIT:
An easy way to create a dependency property is typing the snippet propdp, which will give you the general code for Dependency Properties.
All the code:
XAML:
<Window x:Class="StackOverflowTests.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" x:Name="window1" Height="300" Width="300">
<Grid>
<StackPanel Orientation="Vertical">
<CheckBox Margin="10"
x:Name="myCheckBox"
IsChecked="{Binding ElementName=window1, Path=IsCheckBoxChecked}">
Bound CheckBox
</CheckBox>
<Label Content="{Binding ElementName=window1, Path=IsCheckBoxChecked}"
ContentStringFormat="Is checkbox checked? {0}" />
</StackPanel>
</Grid>
</Window>
C#:
using System.Windows;
namespace StackOverflowTests
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
public bool IsCheckBoxChecked
{
get { return (bool)GetValue(IsCheckBoxCheckedProperty); }
set { SetValue(IsCheckBoxCheckedProperty, value); }
}
// Using a DependencyProperty as the backing store for
//IsCheckBoxChecked. This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsCheckBoxCheckedProperty =
DependencyProperty.Register("IsCheckBoxChecked", typeof(bool),
typeof(Window1), new UIPropertyMetadata(false));
public Window1()
{
InitializeComponent();
}
}
}
Notice how the only code behind is the Dependency Property. Both the label and the checkbox are bound to it. If the checkbox changes, the label changes too.
Hello this is my first time posting so please be patient:
my answer was to create a simple property:
public bool Checked { get; set; }
Then to set the data context of the Checkbox (called cb1):
cb1.DataContext = this;
Then to bind the IsChecked proerty of it in the xaml
IsChecked="{Binding Checked}"
The code is like this:
XAML
<CheckBox x:Name="cb1"
HorizontalAlignment="Left"
Margin="439,81,0,0"
VerticalAlignment="Top"
Height="35" Width="96"
IsChecked="{Binding Checked}"/>
Code behind
public partial class MainWindow : Window
{
public bool Checked { get; set; }
public MainWindow()
{
InitializeComponent();
cb1.DataContext = this;
}
private void myyButton_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show(Checked.ToString());
}
}
Should be easier than that. Just use:
<Checkbox IsChecked="{Binding Path=myVar, UpdateSourceTrigger=PropertyChanged}" />
if you have the property "MyProperty" on your data-class, then you bind the IsChecked like this.... (the converter is optional, but sometimes you need that)
<Window.Resources>
<local:MyBoolConverter x:Key="MyBoolConverterKey"/>
</Window.Resources>
<checkbox IsChecked="{Binding Path=MyProperty, Converter={StaticResource MyBoolConverterKey}}"/>
This works for me (essential code only included, fill more for your needs):
In XAML a user control is defined:
<UserControl x:Class="Mockup.TestTab" ......>
<!-- a checkbox somewhere within the control -->
<!-- IsChecked is bound to Property C1 of the DataContext -->
<CheckBox Content="CheckBox 1" IsChecked="{Binding C1, Mode=TwoWay}" />
</UserControl>
In code behind for UserControl
public partial class TestTab : UserControl
{
public TestTab()
{
InitializeComponent(); // the standard bit
// then we set the DataContex of TestTab Control to a MyViewModel object
// this MyViewModel object becomes the DataContext for all controls
// within TestTab ... including our CheckBox
DataContext = new MyViewModel(....);
}
}
Somewhere in solution class MyViewModel is defined
public class MyViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private bool m_c1 = true;
public bool C1 {
get { return m_c1; }
set {
if (m_c1 != value) {
m_c1 = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("C1"));
}
}
}
}
No backend and ViewModel Code:
I made such check box to control other control's visibility.
<CheckBox x:Name="rulerCheckbox" Content="Is Ruler Visible" IsChecked="True"/>
and in the other control, I added such binding:
Visibility="{Binding IsChecked, ElementName=rulerCheckbox, Mode=TwoWay, Converter={StaticResource BoolVisConverter}}">

Categories

Resources