I have a listview inside user control, and the user control is called on a page. I want to decide what will be the SelectionMode of the ListView from my page. To achieve this I have created a dependency property inside user control like this
public ListViewSelectionMode SelectionMode
{
get { return (ListViewSelectionMode)GetValue(SelectionModeProperty); }
set { SetValue(SelectionModeProperty, value); }
}
public static readonly DependencyProperty SelectionModeProperty =
DependencyProperty.Register("SelectionMode", typeof(ListViewSelectionMode), typeof(EditMultiSelectComboBoxControl), new PropertyMetadata(null));
XAML
<ListView SelectionMode="{x:Bind lvSelectionMode}"></ListView>
And on my main page, I am initializing this user control like this:
<local:myuc Loaded="UC_Loaded" ></local:myuc>
Code behind
private void UC_Loaded(object sender, RoutedEventArgs e)
{
MultiCombo.SelectionMode = ListViewSelectionMode.Multiple;
}
All looks good to me, but when I run the project no item inside Listview is clickable / selectable. What I am missing here?
It is recommended that you use OneWay binding mode, so that after loading, changes to control dependent properties will still be reflected on the UI
<ListView SelectionMode="{x:Bind lvSelectionMode, Mode=OneWay}"></ListView>
Thanks.
Related
I say proper because all the examples I have seen all seem to contradict each other and or fall short in some respects. I need to be able to bind a class object to my DP from XAML or set it programmatically in cb:
<local:MyControl MyDP="{Binding MyObject}"/>
or
MyControl mycontrol = new MyControl(){MyDP = MyObject};
and then within the control, two way bind elements to properties of the binding object:
<TextBox text="{Binding MyDP.text, ElementName=MyControl}"/>
I would think this is pretty standard stuff, but the lack of cohesion I have seen in people trying to write examples has led me to believe otherwise.
This is how I do it:
Assume a parent control that contains a status bar (User Control) it's markup looks like this:
<ContentControl x:Name="XFoot" Grid.Row="1" Grid.ColumnSpan="3" >
<UserControls:UCStatusBar />
</ContentControl>
Now in the UserControl named status bar it's dependency property looks like this:
public StatusUpdate CurrentStatus
{
get { return (StatusUpdate)GetValue(CurrentStatusProperty); }
set { SetValue(CurrentStatusProperty, value); }
}
// Using a DependencyProperty as the backing store for CurrentStatus. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CurrentStatusProperty =
DependencyProperty.Register("CurrentStatus", typeof(StatusUpdate), typeof(UCStatusBar),
new PropertyMetadata(
new StatusUpdate() { ErrorMessage="", IsIndeterminate=false, Status="Ready"}
)
);
Status Update looks like this, it's just a container for three properties shown in the status bar.
public class StatusUpdate
{
public StatusUpdate()
{
Status = "";
ErrorMessage = "";
IsIndeterminate = true;
}
public string Status { get; set; }
public string ErrorMessage { get; set; }
public bool IsIndeterminate { get; set; }
}
}
Anyone can update the status bar by accessing the CurrentStatus property of the statusbar. NOTE to make a two way binding, that's done in XAML... within the binding directive, just press space bar and the property window will show binding modes. Pick two way.
PS: In Visual Studio, when you first create the DP just type in propdp and press the tab button, the entire DP structure is inserted for you automatically. As a result DPs are easy to implement.
How do DPs work two-way?
If you are using XAML binding you simply tell it via the MODE property that it's two way. This means that the GUI changes will update the properties when user changes the values.
<TextBox Text="{Binding Path=ThePropertyName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
Notice the Mode value and the UpdateSourceTrigger says, don't want for focus to change, update it right away.
Wait a minute, nothing is happening when I bind and make changes!
Three things are required for a binding to work 1) DataContext must be set either in code behind or as a static resource in the XAML 2) The pathname to the property name must exactly the CLR property name and 3) There must be content in the property.
Can I fire an Event from somewhere else to update the property?
Sure... the first step is to set up the static eventhandler in the UserControl like this:
public static EventHandler<string> NewData;
Then in the CTOR wire it up like this:
NewData+=OnNewData;
Then the event handler looks like this:
private void OnNewData(object sender, string data){
//setting this string property notifies WPF to update the GUI
ThePropertyName = data;
}
The other code does this...
MyUserControl.OnNewData(this, "Now is the time for all good men to...");
Without breaking MVVM, is there a way to expose some properties of a child control in a user control so that the window or other user control that utilizes it can access these properties directly?
For instance I have a user control that has a listview set up with gridviewcolumns, headers, and is bound to a view model. But the list view in the user control has selected item properties and such that I'd like to expose to the host without having to do something like usercontrol.customListView.property. Or is that how I should do it? I'd like to go just usercontrol.property, omitting customListView. Perhap I should just create properties in the user controls code behind that return the list view controls properties that I want attached directly to the user control?
I feel like that latter option doesn't really break MVVM since they are exposed for the host to interact with, not really related to the view itself. Any suggested would be appreciated.
EDIT: In fact, I'd really like to have a SelectedItem property directly on the user control that is not ListViewItem or object, but actually of the datatype contained that doe like:
public MyDataType SelectedItem {
get {
return customListView.SelectedItem as MyDataType;
}
}
Would that be permissible in MVVM? Because I don't see how I could have that in the ViewModel, seems like it would have to be in the partial class code behind.
This is pretty common task when you want to put something repeated into UserControl. The simplest approach to do so is when you are not creating specialized ViewModel for that UserControl, but sort of making custom control (build with the use of UserControl for simplicity). End result may looks like this
<UserControl x:Class="SomeNamespace.SomeUserControl" ...>
...
<TextBlock Text="{Binding Text, RelativeSource={RelativeSource FindAncestor, AncestorType=UserControl}" ...>
</UserControl>
.
public partial class SomeUserControl : UserControl
{
// simple dependency property to bind to
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(SomeUserControl), new PropertyMetadata());
// has some complicated logic
public double Value
{
get { return (double)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value); }
}
public static readonly DependencyProperty ValueProperty =
DependencyProperty.Register("Value", typeof(double), typeof(SomeUserControl),
new PropertyMetadata((d, a) => ((SomeUserControl)d).ValueChanged()));
private void ValueChanged()
{
... // do something complicated here
// e.g. create complicated dynamic animation
}
...
}
Usage will looks like this in containing window
<l:SomeUserControl Text="Text" Value="{Binding SomeValue}" ... />
As you can see SomeValue is bound to Value and there is no MVVM violations.
Of course, you can create a proper ViewModel if view logic is complicated or required too much bindings and it's rather easier to allow ViewModels to communicate directly (via properties/methods).
I have a MVVM Windows Phone 8 app. The XAML page has a user control that I created that needs to be notified when a change takes place in the View Model. To facilitate this, I created an int property in the user control to be bound to a property in the View Model, so the user control property's setter method would be triggered when the property it was bound to in the View Model changed.
Using the code below, the user control's VideosShownCount property does show up in the Property List at design-time but when I click on the binding mini-button, the Create Data Binding option is greyed out in the pop-up menu.
So I have one or two questions, depending on what is the root problem:
1) How do I make a property in a View Model available as a Data Binding source?
2) How do I format a user control property so the IDE allows it to be data bound to a View Model property?
private int _videosShownCount = 0;
public int VideosShownCount
{
get
{
return this._videosShownCount;
}
set
{
this._videosShownCount = value;
}
}
public static readonly DependencyProperty VideoShownCountProperty =
DependencyProperty.Register("VideosShownCount", typeof(int), typeof(MyUserControl),
new PropertyMetadata(0, new PropertyChangedCallback(VideoShownCountPropertyChanged)));
static void VideoShownCountPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
MyUserControl MyUserUserControl = (MyUserControl)sender;
// Don't care about the value, just want the notification.
// int val = (int)e.NewValue;
// Do work now that we've been notified of a change.
MyUserUserControl.DoWork();
}
You're not using the DependencyProperty for your property, which will definitely cause problems between your code and the bindings
public int VideosShownCount
{
get { return (int) GetValue(VideosShownCountProperty); }
set { SetValue(VideosShownCountProperty, value); }
}
I'm not sure if this is the main cause of your problem, but it's worth fixing regardless.
private void cmbEmployee_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
string employee = (e.AddedItems[0] as ComboBoxItem).Content as string;
dgFake.ItemsSource = newdal2.SelectUser(employee).Tables[0].DefaultView;
}
This method populates the data grid on my WPF windows form by a specific employee when this employee is clicked from a combo box, however, when I click another employee after the first, it doesn't refresh the data grid, but instead adds that employee's data beneath the first.
How do you refresh or delete the items in a Data Grid baring in mind this is on WPF Xaml Windows Forms, and it is not a DataGridView. I have tried these already and none have worked:
dgFake.Items.Refresh();
dgFake.Items.Remove(); //Required a remove item passed to the method, so too specific
dgFake.Itemssource = "";
In general using WPF, we manipulate data, not UI elements. Therefore, after Binding a collection property to the DataGrid.ItemsSource property, we can simply work with the collection property:
In XAML:
<DataGrid ItemsSource="{Binding YourCollection}" ... />
Then in code:
YourCollection.Clear();
Or to change items:
YourCollection = someNewCollection;
You will need to implement the INotifyPropertyChanged interface in order for the DataGrid to update automatically after changing the data like this.
UPDATE >>>
In response to the comment: 'I have added the XAML code, when you talk about 'YourCollection' in the XAML code what needs to be put here?':
You'll need to create a Bindable collection property in your code; this can either be a DependencyProperty in your code behind, or a CLR property that implements the INotifyPropertyChanged interface. We generally don't display database elements in the UI, instead preferring to define object classes with the required properties:
public static DependencyProperty EmployeesProperty = DependencyProperty.Register(
"Employees", typeof(ObservableCollection<Employee>), typeof(YourUserControl));
public ObservableCollection<Employee> Employees
{
get { return (ObservableCollection<Employee>)GetValue(EmployeesProperty); }
set { SetValue(EmployeesProperty, value); }
}
Then in your cmbEmployee_SelectionChanged handler method, you can update the collection property's value with something like this:
private void cmbEmployee_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
Employees = new ObservableCollection<Employee>();
string employee = (e.AddedItems[0] as ComboBoxItem).Content as string;
foreach (DataRow row in newdal2.SelectUser(employee).Tables[0].Rows)
{
Employees.Add(new Employee(row.Id, row.Name, row.Whatever));
}
Employees = newdal2.SelectUser(employee).Tables[0].DefaultView;
}
I've got a ListView which is bound to a list of objects. When I select an item in the ListView, I catch a SelectionChanged event and then pass the selected object off to a details view.
protected void list_selectionChanged(object sender, SelectionChangedEventArgs e) {
var myObject = theList.SelectedItem as MyObjectType;
detailsView.DataContext = myObject;
}
detailsView is a UserControl in the same WPF as the ListView. It contains some XAML like so:
<Label Content="{Binding Path=deviceId}"></Label>
<l:MyUc deviceId="{Binding Path=deviceId}" />
Inside MyUC, I've got a DependencyProperty defined:
public static readonly DependencyProperty deviceIdProperty = DependencyProperty.Register("deviceId", typeof(Guid), typeof(MyUC), new FrameworkPropertyMetadata(null));
public Guid deviceId {
get { return (Guid)GetValue(deviceIdProperty); }
set { SetValue(deviceIdProperty, value); }
}
The Label shows the deviceId, but the property inside MyUC never gets set.
Can anyone spot my mistake?
When you use a Dependency Property in XAML, the set method never gets called. If you want to "see" this set, you need to add a property changed callback, as the binding mechanism directly sets the dependency property without your setter.
For details on how to implement this, see the PropertyChanged callbacks section of MSDN.
First, it would be helpful if you could add the actual XAML code where you define the ListView and it's properties.
Second, you should look at the output console (in Visual Studio debug session of course) and see whether there are binding errors regarding the bindings you defined.
It is very probable that the bindings provide values that does not fit the deviceId dependency property type and thus it never changes.