Using two different events to update a ViewModel property in WPF - c#

I apologize if the question title isn't really specific, I'm not exactly sure how to condense the problem I'm having down to a few words. But to simplifiy the problem I'm having, here is my issue:
I'm creating a tool using WPF that consists of a TextBox that will contain a path to a directory and a Button that will allow you to Browse to a certain directory. Now, when I select the Browse button, it pops up a dialog, allows the user to select a directory and then I have some methods that will disable some buttons and updates some Brushes on the screen if the path doesn't meet a certain set of criteria. No problems there, got that working.
My problem is the TextBox that this Browse button correlates with. This TextBox is using a binding as such:
In my MainWindow.xaml (Yes, this is the simplified, focused version):
<Window>
<TextBox Text="{Binding Directory}" TextChanged="Directory_TextChanged" />
<Button Content="Browse..." Click="Browse_Click"/>
</Window>
In my code MainWindow.xaml.cs file:
public partial class MainWindow: Window
{
private ViewModel myViewModel;
public MainWindow()
{
myViewModel = new ViewModel();
this.DataContext = myViewModel;
}
private void Browse_Click(object sender, RoutedEventArgs e)
{
// Dialog stuff that's working
viewModel.Directory = dialog.SelectedPath;
}
private void InstallDir_TextChanged(object sender, TextChangedEventArgs e)
{
ValidatePath(); /* Disables/enables buttons and updates brushes based on validation. Also working */
}
private void ValidatePath() {/* */}
}
Like I mentioned earlier, the browse button works fine. I'm trying to figure out however, how I can get this to work if I type a directory alongside it. Because if I type something in the textbox, that would mean that inside of the InstallDir_TextChanged() function I would have to set viewModel.Directory, but since I have the INotifyPropertyChanged attached to this ViewModel, this function would get called recursively.
I tried doing the validation stuff within the viewmodel, but I couldn't figure out how to update the brushes/buttons in MainWindow if I did this. (Still relatively new to C# so I haven't learned the ins and outs yet. This is the first WPF tool I've been making from scratch, so just a disclaimer).
Would anyone have any ideas (or logic) I can approach to try and accomplish this? If there's any further clarification needed, that's not an issue. I don't need an exact definitive answer. Maybe some advice that could point me in the correct direction would definitely suffice. I don't have a problem trying to figure stuff out.

Related

Visual Studio/C# Issues with .Checked Boxes In User Settings

So I'm dabbling in C# properly for the first time trying to make a WPF based desktop application.
So far it's mostly going well, however as part of the project I am trying to take input from the user in one window (essentially where they define a project and the settings they want) and save them for later user in the project and have it act accordingly based on their input.
I've figured out the saving of this data for text inputs etc, however I'm having issues replicating this for check boxes.
I've defined the setting in the settings page as a bool defaulting to false, with the intent to be if the user ticks the checkbox then set the setting to true for later use.
When I'm trying to use .Checked against my checkbox class name it says it must appear on the left hand side of of += or -=, I've looked online for clarification and most similar code & relevant tutorials define it the way I have without issue.
Here's a snippet of the code:
public void CXML_GetSettings()
{
CXML_NewProject_Inc_SubModule_XML.Checked = Properties.Settings.Default.CXML_Project_Inc_SubModule;
}
Tried various ways of changing it but just can't get .Checked to work anywhere.
The Checked is an event for CheckBox, if you want to use it for your CheckBox, you can use it like below:
public MainWindow()
{
InitializeComponent();
MyCheckBox.Checked += MyCheckBox_Checked;
}
private void MyCheckBox_Checked(object sender, RoutedEventArgs e)
{
throw new NotImplementedException();
}
Or
<CheckBox IsChecked="False" Name="MyCheckBox" Checked="MyCheckBox_Checked"/>
private void MyCheckBox_Checked(object sender, RoutedEventArgs e)
{
throw new NotImplementedException();
}

C# / WPF - Getting object inside a child user control from parent window

Not terribly familiar with WPF and C# so if this is blatantly wrong, please correct me. Working in VSExpress2015 .NET Framework 4.5. I'm heavily simplifying my code below, so know that namespace/library references are there.
Say I have a window with a Button and ContentControl inside:
<Window x:Class="Project.MainWindow">
<Grid>
<Button Name="Submit_Btn" Click="Submit_Btn_Click">
<ContentControl Name="MainContentControl">
</Grid>
</Window>
I also have several user control files in my project with XAML that looks something like this:
<UserControl x:Class="Project.UserControl1">
<Grid>
<TextBox Name="TxtBox1">
</Grid>
</Usercontrol>
I have code in the backend of my MainWindow to dynamically load the appropriate UserControl into the "MainContentControl" object. However, I want to reference the objects inside of the currently loaded UserControl from the MainWindow's Submit_Btn_Click function. For example, in MainWindow.cs, do something like this:
private void Submit_Btn_Click(object sender, RoutedEventArgs e)
{
if(MainContentControl is currently loaded with UserControl1)
Do_Something_Function(MainContentControl.TxtBox1.Text);
}
The main problem here is I don't know how to call the TextBox1 element from within the parent MainWindow's scope. I'm also not sure how to validate the if condition (confirming the control is currently loaded). Does anyone know of a way to think about this differently or even directly reference the object (despite that probably not being a great idea)?
--
I'm not using/familiar with MVVM at all (yet), and I'm not particularly concerned with optimal performance as this is a one off temporary project that will soon die and be re-worked. I've read ways how to access the data in a parent window from a child, but I didn't find scenarios that really matched up with this.
Once again, I'm still familiarizing myself with C#, WPF and general coding practices (it's been a couple years), so if using a ContentControl or UserControl here isn't optimal, (or mixing the two doesn't make sense) that information would be greatly appreciated; however, in this scenario, I'm more concerned with just getting this working until I can learn more proper techniques later.
Instead of trying to access the TextBox inside the UserControl, you can expose properties and methods on the UserControl itself to interact with what's inside. In your case, you could add a property that returns the current value of TextBox.Text. You can also add dependency properties to facilitate binding.
You can use the LogicalTreeHelper to search by name.
So for your example to access TextBox1
var txtBox = LogicalTreeHelper.FindLogicalNode(MainContentControl, "TextBox1") as TextBox;
Do_Something_Function(txtBox?.Text);
It definitely looks like the design should be improved, but just to get this working you can do the following:
private void Submit_Btn_Click(object sender, RoutedEventArgs e)
{
var controlAsUserControl1 = MainContentControl.Content as UserControl1;
if (controlAsUserControl1 != null)
{
Debug.WriteLine(controlAsUserControl1.TxtBox1.Text);
}
}

Function binding normative

I'm new to WPF and MVVM and am going through an example on Microsoft's site, however, I don't see how the binding is done. In the example linked, there's this piece of code:
public partial class MainPage : UserControl
{
private PartInventoryViewModel viewModel;
public MainPage()
{
InitializeComponent();
viewModel = new PartInventoryViewModel();
this.DataContext = viewModel;
}
private void PartSearchButton_Click(object sender, RoutedEventArgs e)
{
viewModel.GetParts();
}
}
Apparently:
It notifies the ViewModel instance when the user clicks the PartSearchButton.
But how? There's no binding in the XAML above for the PartSearchButton in the example. Is it a normative that if you name your function YourButtonName_Clicked() it will trigger when the button is clicked? Or does it become a listener if you create the function with the (object sender, RoutedEventArgs e) arguments? Or is there some XAML which this tutorial is not showing, where the binding occurs?
Thank you for your answer, sorry if it's a newb one.
Microsoft is not showing all the code that is necessary here. Basically all that this code does is setting the DataContext to a newly instantiated ViewModel. The PartSearchButton_Click is a simple Click-Event-Handler that should look something like this in your XAML-file:
<Button Click="PartSearchButton_Click">Search</Button>
The whole binding thing is happening in these 2 lines of the datagrid in your xaml file:
ItemsSource="{Binding Parts}"
SelectedItem="{Binding CurrentPart, Mode=TwoWay}"
This is telling the DataGrid that it should look for a public property called Parts in the current DataContext. You set the DataContext to a new instance of PartInventoryViewModel, so there needs to be a public property Parts somewhere in there. I guess the PartInventoryViewModel class will be explained a bit further down on the Microsofts site.
The XAML snippets from your link are effectively missing that event handler.
The <source>_<event> guideline is the convention for naming event handlers, but by no means the function gets automatically bound to the corresponding event; you have to add the handler either programmatically or in XAML.
That said, associating application logic to buttons is usually done in WPF by means of commands instead of event handlers. The view model exposes a property of type ICommand, anf the view binds the Command dependency property of a Button (or other controls) to it. How that command is implemented under the hood is completely irrelevant to the view.

WPF Extended ToolKit - Selecting value in DecimalUpDown

After hours of trying to solve this, I'm giving up and am actually wondering if there's a solution for this.
I have a WPF View that is setting the focus on a decimal up down from the code behind (xaml.cs). My aim is to select the value inside it since it loads "0.00" and it's frustrating for the user to have to delete it before he enters his value. I tried the following code in the loaded method:
private void Loaded_Window(object sender, EventArgs e)
{
txtAmount.AutoSelectBehavior = AutoSelectBehavior.OnFocus;
txtAmount.Focus();
Keyboard.Focus(txtAmount);
}
I have also tried to set SelectAllOnGotFocus as true and it still did not work. Funnily enough, this selects the test if I put a debug point in the method so I'm thinking that it has to do with the loading of the User Control. Does anyone have any pointers of how to make this work?
The xaml decimalupdown:
<xctk:DecimalUpDown x:Name="txtAmount" d:LayoutOverrides="Height" Minimum="0" Maximum="99999999.99" ShowButtonSpinner="False" UpdateValueOnEnterKey="True" Text="{Binding Amount, UpdateSourceTrigger=PropertyChanged}" AllowSpin="False" FormatString="N2" >
Try the following:
private void [NAME OF YOUR EVENT GOES HERE] (object sender, KeyboardFocusChangedEventArgs e)
{
if (e.KeyboardDevice.IsKeyDown(Key.Tab))
{
SelectAll();
}
}
The "SelectAll" is really the main thing here, you can ignore the if statement i believe.
In the XAML you will have to add the property "GotFocus" to your control like so:
<xctk:DecimalUpDown GotFocus="[NAME OF YOUR EVENT GOES HERE]" />
So that whenever it gains focus, the first thing it does is select everything ready for editing.

Multiple XAML layouts in WPF

App I am trying to create in WPF/C# has quite a few buttons in a layout with a "TV screen" type panel above (its actually an FMS emulator for commercial aircraft). Many of the buttons change the layout, which are numerous TEXTBOXs on the tv screen. My question is: is there a provision to encapsulate the layouts in different classes/files and load them into the "tv screen" at the selection of the various buttons? In other words, user hits the Flight Plan button and the layout of the 355x355 box (screen) above loads the XAML "flight_plan" layout/file/class. Each layout has different TEXTBOX sizes & locations and there are in excess of 30 different "pages", which would make encapsulating them desirable.
I am very new to WPF and c#, but have written win apps in c++ all the way back to Turbo C & OWL. I also may be trying to do something that isn't possible due to working lately in Android/Java and am confusing capabilities.
Thanks in advance.
Edit
Thanks to #adityaswami89 and everyone else who got me on the right track, I have found the solution. I added the pages via a new "WPF Page" in VS2012. Then changed the "screen" to a navigation frame and it was truly simple from there. Below is the simple project I created to test it.
public partial class MainWindow : Window
{
NavRad navrad = new NavRad();
FPlan fplan = new FPlan();
public MainWindow() {..}
private void Frame_Navigated_1(object sender, NavigationEventArgs e) {..}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
Screen_Frame.Navigate(fplan);
}
private void Button_Click_2(object sender, RoutedEventArgs e)
{
Screen_Frame.Navigate(navrad);
}
You can also use the concept of Frames for the intended functionality , if that can be an option you are looking.
You can refer the below link for the same.
http://msdn.microsoft.com/en-us/library/ms750478.aspx#Frame_in_Standalone_Applications
You can abstract the different UI Layout Sets within different User Controls and load them according your UI logic. One way to do this is using an MVVM framework, for example, Caliburn Micro makes this a pretty simple task as doing:
ActivateItem(UILayoutViewModel);
And this call can be called from any method.
See more of Caliburn Screens and Composition at official source.

Categories

Resources