WPF Very Beginner Issue - Setting Default Control Values - wpf

Here is a very basic question from a WPF novice.
I have a form with some controls such as TextBoxes, DatePickers for example.
In a typical Windows Forms, I would set default values to these in onFormLoad event like
txtName.Text = "N/A";
dpStartDate.Value = DateTime.Now(5); //set 5 days from now
dpEndDate.Value = DateTime.Now(10); //set 10 days from now
How to do this in WPF form and where? This is a very beginner question, where to do it the right WPF-way?
UPDATE:
So far, I have found that I can do this in Window_Loaded event like:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// Initialize Employee Data
txtName.Text = "N/A";
dpEmplDate.Text = DateTime.Now.AddDays(-100).Date.ToString();
dpTermDate.Text = DateTime.Now.AddDays(1).Date.ToString();
txtAddress.Text = "N/A";
dpDateOfBirth.Text = "";
txtDepartment.Text="N/A";
...
...
}
So, I am setting default employee values like this.
My question is, is this proper WPF way to initialize data?
Thanks,

There is no preferences to set values to Controls till you are not using MVVM pattern.
You can do it in XAML:
<TextBox Name=txtName Text="N/A"/>
or in code-behind:
txtName.Text = "N/A";
But WPF is very cool technology cause it can provide clean separation of concerns between data and view. It can be achieved using MVVM pattern.
It possible to use Binding to send data between data and view and from view to data. So in MVVM pattern data is set from view model. The example of syntax:
View:
<TextBox Text="{Binding FooProperty}"/>>
ViewModel:
public class FooViewModel
{
private string fooProperty="Hello World";
public string FooProperty
{
get { return fooProperty; }
set { fooProperty = value; }
}
}
DataContext property uses to connect View and ViewModel. Data from ViewModel will not be shown without setting DataContext property .

Related

Custom Usercontrol with MVVM and Catel

I've created a custom usercontrol that's composed of a AutoCompleteBox with a Selected Item... till now I've implemented it in a way I don't like... I mean I've a XAML view, a Viewmodel and in the viewmodel I load data from a stored procedure.
Since the AutoComplete box is a third party UserControl I've added it to the XAML view and not defined as a custom usercontrol. What's the best practice to do so?
I think the fact that I'm using Catel as MVVM Framework is irrilevant right now..
Thanks
UPDATE #1
My usercontrols need to have some properties that are passed via XAML for example (LoadDefaultValue)
<views:PortfolioChooserView x:Name="PortfolioChooserView" DataContext="{Binding Model.PortfolioModel}" Height="25" LoadDefaultValue="True" Width="150" />
To achieve such a scenario I had to define a dependency property in my PortfolioChooserView defined as
public bool LoadDefaultValue
{
get { return (bool)GetValue(LoadDefaultValueProperty); }
set { SetValue(LoadDefaultValueProperty, value); }
}
public static readonly DependencyProperty LoadDefaultValueProperty = DependencyProperty.Register(
"LoadDefaultValue", typeof(bool), typeof(PortfolioChooserView), new PropertyMetadata(default(bool)));
Since if I would have defined it in Viewmodel only I wouldn't have been able to set it.
The odd thing is that in order to pass it to the viewmodel I had to do such a trick
public PortfolioChooserView()
{
InitializeComponent();
if (!isFirstLoad) return;
Focusable = true;
PortfolioCompleteBox.AllowDrop = true;
PortfolioCompleteBox.Focus();
DragDropManager.AddPreviewDragOverHandler(PortfolioCompleteBox, OnElementDragOver);
DragDropManager.AddDropHandler(PortfolioCompleteBox, OnElementDrop);
DataContextChanged += PortfolioChooserView_DataContextChanged;
isFirstLoad = false;
}
void PortfolioChooserView_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
var dataContext = DataContext as PortfolioModel;
if (dataContext != null)
{
dataContext.LoadDefaultValue = LoadDefaultValue;
dataContext.AllowNull = AllowNull;
//var converter = new PortfolioConverter();
//var portfolio = (Portfolio) converter.Convert(SelectedItem, null, null, CultureInfo.CurrentCulture);
//dataContext.SelectedItem = portfolio;
}
}
But I really dislike to use the DataContextChanged event ...do you see a better approach?
Thank
UPDATE#2
I keep this toghether since It's a related question...
On some viewmodel I used DeferValidationUntilFirstSaveCall = true; in the Constructor to disable the validation at load but my custom usercontrols shows the red border around... what should I do to propagate that info to the nested usercontrols?
Thanks again
See Orc.Controls for tons of examples. It's an open-source library that has a lot of user controls built with Catel, even one with an auto complete box.

How can I bind Pushpin location in WPF using MVVM?

I'm developing a Desktop application that uses Bing maps and MVVM.
In the application, a user adds a Pushpin in the map by double clicking on it, the Pushpin location gets saved in an Event class and the Event class is sent through a WCF Service.
I would like to get the Latitude and Longitude from the Pushpin using data binding, however the compiler complains about DependencyProperty when I try to do that.
I managed to set the Latitude and Longitude in the ViewModel from the View, however I don't know if it's valid in MVVM. I have seen examples using MapsItemControls but I don't understand them.
ViewModel
private Event evt;
public Event Evt
{
get
{
return this.evt;
}
set
{
this.evt = value;
OnPropertyChanged("Event");
}
}
Map xaml
<m:Map Grid.RowSpan="5" Grid.Column="3" Margin="3"
Name="operatorMap"
CredentialsProvider="Map_key"
Center="19.4000,-99.1333"
ZoomLevel="5"
MouseDoubleClick="SetPushpinLocation" />
CodeBehind
private MaintenanceFormViewModel viewModel = new MaintenanceFormViewModel();
private Pushpin pin = null;
public MainWindow()
{
InitializeComponent();
this.Loaded += (s, e) =>
{
this.DataContext = this.viewModel;
};
}
private void SetPushpinLocation(object sender, MouseButtonEventArgs e)
{
e.Handled = true;
Point mousePosition = e.GetPosition((UIElement)sender);
Location pinLocation = operatorMap.ViewportPointToLocation(mousePosition);
if (pin == null)
{
pin = new Pushpin();
operatorMap.Children.Add(pin);
}
pin.Location = pinLocation;
this.viewModel.Evt.Latitude = pinLocation.Latitude;
this.viewModel.Evt.Longitude = pinLocation.Longitude;
}
Bing Maps uses the attached property MapLayer.Position for positioning elements on the map.
Given a view model with a property of type Location
public class ViewModel : INotifyPropertyChanged
{
private Location location;
public Location Location
{
get { return location; }
set
{
location = value;
OnPropertyChanged("Location");
}
}
...
}
you can bind the position of a Pushpin like this:
<bm:Pushpin bm:MapLayer.Position="{Binding Location}"/>
Note that in the Windows Store App version of the Bing Maps SDK there seems to be a bug when you try to setup a binding in XAML. It says (still with Bing Maps SDK version 1.313.825.0)
Failed to assign to property 'Bing.Maps.MapLayer.Position'
You can however create a binding in code behind:
pushpin.SetBinding(MapLayer.PositionProperty,
new Binding { Path = new PropertyPath("Location") });
Personally, I'd add an attached property to the Bing map which would allow you to bind the lat/long to properties to your ViewModel. This would follow the MVVM pattern.
Google "attached property wpf" for a tutorial on attached properties, there are some good ones out there.
This is not to say that using code behind is bad: usually I get it working with code behind first, then port it into an attached property to adhere to the MVVM pattern, and for reusability and maintainability.
You mentioned an error related to dependecy properties. These are completely different to attached properties.
You add a dependency property to a user control that you write yourself.
You add an attached property to another 3rd party control you cannot alter or do not have the source code for. The rule of thumb is this: if you start with any code behind in a user control, you can shift it into an attached property to keep in line with the MVVM pattern.
Yes, attached properties are a bit of a learning curve, but persevere: this is one technique you will have to master before you can become an MVVM expert.

WPF Bind control to DataView

I am having a LOT of trouble trying to bind my controls to a data source. I tried binding to XML document. That worked, but lots of issues when I tried to refresh the XML document itself and have it update the UI.
My newest try is to bind my controls to a DataView, which seems simple. I have a sample app I found here on StackOverflow, which does this:
public MainWindow()
{
InitializeComponent();
DataTable dataTable = GetTable();
Binding dataTableBinding = new Binding();
dataTableBinding.Source = dataTable;
dataTableBinding.Path = new PropertyPath("Rows[0][MyTextColumn]");
txtMyTextColumnDataTable.SetBinding(TextBox.TextProperty, dataTableBinding);
DataView dataView = dataTable.DefaultView;
Binding dataViewBinding = new Binding();
dataViewBinding.Source = dataView;
dataViewBinding.Path = new PropertyPath("[0][MyTextColumn]");
txtMyTextColumnDataView.SetBinding(TextBox.TextProperty, dataViewBinding);
}
This works perfectly, right out of the box. I added a button whose code updates the value in the data table, and the textbox immediately reflects the new value when I click that button.
I tried this in my VB.Net project, like this:
dim plcData As DataTable = GetTable()
dim plcView As DataView = plcData.DefaultView
dim plcBinding As Binding = New Binding
plcBinding.Source = plcView
plcBinding.Path = New PropertyPath("(0)(conveyor_plc_data_Main_FeedCarousel_caroAngle)")
Me.tb.SetBinding(TextBlock.TextProperty, plcBinding)
And it doesn't work. It will not update my UI control.
In both cases, GetTable builds a 1-row DataTable with sample data. In my VB project, tb is a TextBlock on my MainWindow.
In the VB project, I can interrupt my code and query the particular data column in the Immediate window, and the proper value is there. It just won't update into my control.
This seems like a very simple thing to do. I am quite new to WPF, and can't see what is wrong with my code. Eventually I would like to define the binding in my XAML, but can't figure out how to do this. At this point, a code-behind setting of the binding would be ok. I will have many controls to be bound to many data columns.
Can anybody tell me what obvious thing I'm missing here?
According to the documentation, the syntax for the PropertyPath class only accepts C#-style indexers.
Single Indexer on the Immediate Object as Data Context:
<Binding Path="[key]" .../>
The class has no way to change its syntax based on the calling language.
EDIT
To set the binding in XAML when the DataView is created in the code-behind, expose the view as a property:
public static readonly DependencyProperty plcViewProperty
= DependencyProperty.Register("plcView", typeof(System.Data.DataView),
typeof(MainWindow), new PropertyMetadata(null));
public System.Data.DataView plcView
{
get { return (System.Data.DataView)GetValue(plcViewProperty); }
set { SetValue(plcViewProperty, value); }
}
private void MainWindow_Initialized(object sender, EventArgs eventArgs)
{
plcView = GetTable().DefaultView;
}
Then in your XAML:
<Window x:Name="TheWindow" ...>
...
Text="{Binding ElementName=TheWindow,
Path=plcView[0][conveyor_plc_data_Main_FeedCarousel_caroAngle]}"

WPF & MVVM : Update an image field without breaking the pattern

I'm currently learning how to write a WPF application using the MVVM pattern. I'm writing a little contact manager application, so my app displays a Listbox bound to my View Model, and a set of fields bound to ListBox.SelectedItem. One of these fields is the contact's photo.
I'd like to change the photo in the edit part using OpenFileDialog, so the Listbox item would be updated, as it is for all of the other fields.
I first tried to update the source property of the Image control, but doing this, I lose the Binding...
Then I wrote an handler on Button_Click to update the Contact.Photo property (its type is byte[]), and it works. But instead of binding from the "update control" to the view model, binding is from the VM to the control, as if the data came from the DB.
(In the code, LoadPhoto returns a byte[])
private void Button_Click(object sender, RoutedEventArgs e)
{
OpenFileDialog OpenFileDialog = new OpenFileDialog();
if (OpenFileDialog.ShowDialog() == true)
{
(listbox.SelectedItem as ContactManager.ViewModel.Contact).Photo =
LoadPhoto(OpenFileDialog.FileName);
}
}
I wonder if it doesn't break the MVVM pattern... I'm not sure of what could be made in the View... Is it the right way to update the Contact object ? Does anyone have a better solution to this problem ?
Look into binding your button to a Command Binding instead of the click event.
You can find implementations of DelegateCommand using Google.
Next you can expose a ImageSource from your ViewModel that you can bind to your Image from your XAML.
I've included some code fragments to get you started.
Once you get past the basics take a look at MVVM Frameworks, like Cinch, you'll find a way to handle OpenFileDialog using the Services Interfaces IOpenFileService.cs to not violate the MVVM pattern.
Here is the XAML:
<Button Content="Update Photo" Command="{Binding UpdatePictureCommand}"/>
<Image Source="{Binding EmployeePicture}"
VerticalAlignment="Center" HorizontalAlignment="Center"
Stretch="Fill" />
Here is the ViewModel:
public MainViewModel()
{
UpdatePictureCommand = new DelegateCommand<object>(OnUpdatePictureCommand, CanUpdatePictureCommand);
}
public ICommand UpdatePictureCommand { get; private set; }
private void OnUpdatePictureCommand(object obj)
{
OpenFileDialog OpenFileDialog = new OpenFileDialog();
if (OpenFileDialog.ShowDialog() == true)
{
//(listbox.SelectedItem as ContactManager.ViewModel.Contact).Photo =
// LoadPhoto(OpenFileDialog.FileName);
Stream reader = File.OpenRead(OpenFileDialog.FileName);
System.Drawing.Image photo = System.Drawing.Image.FromStream((Stream)reader);
MemoryStream finalStream = new MemoryStream();
photo.Save(finalStream, ImageFormat.Png);
// translate to image source
PngBitmapDecoder decoder = new PngBitmapDecoder(finalStream, BitmapCreateOptions.PreservePixelFormat,
BitmapCacheOption.Default);
EmployeePicture = decoder.Frames[0];;
}
private bool CanMoveFirstCommand(object obj)
{
return true;
}
private ImageSource _employeePicture;
public ImageSource EmployeePicture
{
get
{
return _employeePicture;
}
set
{
_employeePicture = value;
OnPropertyChanged("EmployeePicture");
}
}

Loading and binding a serialized view model to a WPF window?

I'm writing a one-window UI for a simple ETL tool. The UI consists of the window, the code behind for the window, a view model for the window, and the business logic. I wanted to provide functionality to the users to save the state of the UI because the content of about 10-12 text boxes will be reused between sessions, but are specific to the user. I figured I could serialize the view model, which contains all the data from the textboxes, and this works fine, but I'm having trouble loading the information in the serialized XML file back into the text boxes.
Constructor of window:
public ETLWindow()
{
InitializeComponent();
_viewModel = new ViewModel();
this.DataContext = _viewModel;
_viewModel.State = Constants.STATE_IDLE;
Loaded += new RoutedEventHandler(MainWindow_Loaded);
}
XAML:
<TextBox x:Name="targetDirectory"
IsReadOnly="true"
Text="{Binding TargetDatabaseDirectory, UpdateSourceTrigger=PropertyChanged}"/>
ViewModel corresponding property:
private string _targetDatabaseDirectory;
[XmlElement()]
public string TargetDatabaseDirectory
{
get { return _targetDatabaseDirectory; }
set { _targetDatabaseDirectory = value; OnPropertyChanged(DataUtilities.General.Utilities.GetPropertyName(() => new ViewModel().TargetDatabaseDirectory)); }
Load event in code behind:
private void loadState_Click(object sender, RoutedEventArgs e)
{
string statePath = this.getFilePath();
_viewModel = ViewModel.LoadModel(statePath);
}
As you can guess, the LoadModel method deserializes the serialized file on the user's drive.
I couldn't find much on the web regarding this issue. I know this probably has something to do with my bindings. Is there some way to refresh on the bindings on the XAML after I deserialize the view model? Or perhaps refresh all properties on the view model? Or am I completely insane thinking any of this could be done?
Thanks.
Assuming that your loadState_Click event is on the Window code behind you could try this.
private void loadState_Click(object sender, RoutedEventArgs e)
{
string statePath = this.getFilePath();
this.DataContext = ViewModel.LoadModel(statePath);
}

Resources