In Silverlight5 how to reference a Thing class from XAML:
xmlns:UserControls="clr-namespace:xyz.ClientApp.UserControls"
public class Thing : ContextMenu, IDisposable
{
public void Dispose()
{
MethodInfo infos = typeof(ContextMenu).GetMethods(BindingFlags.NonPublic | BindingFlags.Instance).Where(a => a.Name.Equals("HandleRootVisualMouseMove")).FirstOrDefault();
Delegate handler = Delegate.CreateDelegate(typeof(MouseEventHandler), this, infos);
EventInfo info = System.Windows.Application.Current.RootVisual.GetType().GetEvent("MouseMove");
info.RemoveEventHandler(System.Windows.Application.Current.RootVisual, handler);
}
}
Am trying to fix a bug in ContextMenuService here
I think you are confusing attached properties and object instantiation syntax. ContextMenu is attached property of ContextMunueService and can not be accessed through your Thing class.
I havent tested it, but following code should work:
<controlsInputToolkit:ContextMenuService.ContextMenu>
<UserControls:Thing>
<!-- menu items here -->
</UserControls:Thing>
</controlsInputToolkit:ContextMenuService.ContextMenu>
Related
I'm using prism regions in order to create dynamic TabControl. But I'm having a problem passing the object from TabItem (parent view) to its child regions.
The below is the code I'm using to build the TabControl.
Shell:
xaml
<ContentControl regions:RegionManager.RegionName="ShellProjectRegion" />
ShellViewModel
regionManager.RegisterViewWithRegion(ShellProjectRegion, typeof(ProjectTabView));
ProjectTabView:
xaml
<TabControl regions:RegionManager.RegionName="ProjectTabRegion">
ProjectTabViewModel
container.RegisterType<object, ProjectView>(typeof(ProjectView).FullName);
ProjectView:
xaml
<Grid>
<ContentControl regions:RegionManager.RegionName="ProjectExplorerRegion"
regions:RegionManager.RegionContext="{Binding}" />
</Grid>
ProjectViewModel
public class ProjectViewModel : BindableBase, INavigationAware, IActiveAware {
private ProjectItem _project;
public ProjectItem Project {
get { return _project; }
set { SetProperty(ref _project, value); }
}
public ProjectViewModel(IRegionManager regionManager) {
regionManager.RegisterViewWithRegion("ProjectExplorerRegion", typeof(ProjectExplorerView));
}
public void OnNavigatedTo(NavigationContext navigationContext) {
Project = (ProjectItem)navigationContext.Parameters["project"];
}
}
ProjectExplorerView:
xaml.cs
public ProjectExplorerView(IUnityContainer container) {
InitializeComponent();
var vm = container.Resolve<ProjectExplorerViewModel>();
RegionContext.GetObservableContext(this).PropertyChanged += (s, e) => {
var context = (ObservableObject<object>)s;
var projectVm = (ProjectViewModel)context.Value;
vm.ParentProjectInfo = projectVm.Project.ProjectInfo;
};
DataContext = vm;
}
Note: Please note that in the last piece of code inside the ProjectExplorerView.xaml.cs the view constructor gets called multiple times each time new Tab is created. when tracing the code, the context variable gets null sometimes, and sometimes has the right value, which is the project I want to pass. but the it's always null at the end of calling the constructor.
So I'm not sure if this is the right way to do it, but it works.
First I've removed regionManager.RegisterViewWithRegion("ProjectExplorerRegion", typeof(ProjectExplorerView)); from ProjectViewModel to ShellViewModel, this was causing the view to be called multiple times as I have mentioned at the end of my question.
Second update the ParentProjectInfo implementation to use INotifyPropertyChanged, and inside the property setter, update what needs to be automatically updated.
I'm using MVVM light toolkit to handle a button click. If I do:
CustomerSaveCommand = new RelayCommand(
() => CustomerSave(),
()=> true);
private void CustomerSave() {
customer.Address="My Street";
}
The function is invoked but the Address field bound in the UI is not updated.
If I put customer.Address="1234" in the ViewModel constructor, the UI IS updated. What am I doing wrong?
EDITED:
The problem is really strange: if I do viewModel.customer.City = "CITY1" in the window load it runs, if I add a button and, in the code-behind click, I add viewModel.customer.City = "CITY2" it does not work.
The customer object in your viewmodel needs to implement the INotifyPropertyChanged interface.
Then in the Address Property setter, you would invoke the PropertyChanged event.
Alternatively, your viewModel can implement the INotifyPropertyChanged interface, and could wrap the Address property and call the PropertyChanged event. You would have to update your bindings, but your model objects wouldn't have to implement any interfaces.
The reason you're seeing that the address is showing up when you modify the object in the constructor is because binding has not taken place yet. In order for the UI to be updated you need to instruct the binding engine that a property binding has changed. To do that you use the INotifyPropertyChanged interface.
try something like this:
public class AutoDelegateCommand : RelayCommand, ICommand
{
public AutoDelegateCommand(Action<object> execute)
: base(execute)
{
}
public AutoDelegateCommand(Action<object> execute, Predicate<object> canExecute)
: base(execute, canExecute)
{
}
event EventHandler ICommand.CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
}
I am doing a simple WPF application using MVVM and I am having trouble binding to the SelectedItem property of the combobox.
The setter of the bound property does not get called, and there is no output in the debug windows telling me it is not able to bind (I assume it is able to).
This is .NET 3.5, I made a small example that has the same problem.
In XAML:
<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<StackPanel>
<ComboBox IsDropDownOpen="False" IsReadOnly="False" ItemsSource="{Binding Path=Printers}" SelectedIndex="0" SelectedItem="{Binding Path=Printer.SelectedPrinter, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" Name="cmbPrinters" />
</StackPanel>
</Window>
View code behind:
using System.Windows;
public partial class Window1 : Window
{
ViewModel viewmodel;
public Window1()
{
viewmodel = new ViewModel();
this.DataContext = viewmodel;
InitializeComponent();
}
}
View model:
using System;
using System.Collections.ObjectModel;
public class ViewModel
{
public ViewModel()
{
Printers = new ObservableCollection<string>() { "test", "test2" };
Printer = new PrinterViewModel();
}
public PrinterViewModel Printer { get; set; }
public ObservableCollection<string> Printers { get; set; }
}
PrinterViewModel:
using System.Windows;
using System.Diagnostics;
public class PrinterViewModel : DependencyObject
{
public string SelectedPrinter
{
get { return (string)GetValue(SelectedPrinterProperty); }
set
{
SetValue(SelectedPrinterProperty, value);
Debug.WriteLine("!!!!!! SelectedPrinter setter called");
}
}
public readonly DependencyProperty SelectedPrinterProperty =
DependencyProperty.Register("SelectedPrinter", typeof(string), typeof(PrinterViewModel), new UIPropertyMetadata());
}
Can anyone see what I am doing wrong here?
The problem here is that you have a misunderstanding about how the Silverlight dependency property system works.
When the value of a dependency property changes, Silverlight doesn't go through the properties you've defined (such as SelectedPrinter) to set the value of the dependency property. The Silverlight dependency property mechanism keeps track of all of the values of dependency properties, and when the value of one of these properties changes, Silverlight changes its value directly without calling your code to do so. In particular, it will not call your property setter. This should explain why your debugging message wasn't appearing.
The getter in a property that uses a dependency property, such as your SelectedPrinter property, should contain only a call to GetValue, and the setter should contain only a call to SetValue. You shouldn't add any code to the getter or setter, as doing this will not achieve what you want.
Furthermore, you are using dependency properties in the view-model layer. This is not where they are intended to be used. Dependency properties are only intended to be used in the view-layer. Your view-model classes should instead be implementing INotifyPropertyChanged rather than extending DependencyObject.
It is possible to bind two dependency properties together. This is permitted, and occasionally it comes in useful to wire together two dependency properties in the view-layer. In fact, the bindings in your example were working, which explains why you weren't getting any messages about problems with bindings.
why inherit from DependencyObject when doing mvvm?`
public class PrinterViewModel : INotifyPropertyChanged
{
private string _selected;
public string SelectedPrinter
{
get { return this._selected; }
set
{
_selected= value;
OnPropertyChanged("SelectedPrinter");
}
}
}
now your code should work
I have a user control in XAML code (a data grid) with this databind statement:
<WpfToolkit:DataGrid ItemsSource="{Binding Path=MyCollection}" x:Name="lvItems"
I use this user control in a presenter class where I istantiate a modelview class and set datacontext to an object in my view
...so MyCollection object is defined in may view class and not in the code behind of my control
but I Want to access this MyCollection property from codebehind because I want to implement a button event that filter my collection source
how can I access to MyCollection in codebehind or where i wrong...?
thanks
maybe something like that?
put this at your button click event or the button command
var yourModelView = this.DataContext as IYourModelView;
if (yourModelView != null) {
var yourColl = yourModelView.MyCollection;
// do something with this collection
}
EDIT
public IYourModelView
{
ICollection MyCollection {get; set;}
}
public class YourModelView1 : IYourModelView
{}
public class YourModelView2 : IYourModelView
{}
hope this helps
in my Silverlight 4 project, I like to bind an ReadOnlyObservableCollection to a Button Property. The collection is part of a class, which binds to the DataContect of the UserControl, that contains the Button.
<Button Visibility="{Binding Children, Converter={StaticResource ConvertHasListItems2Visibility}}" />
The converter is called the first time, when the control is created, but after that, it isn't called when I add or remove items to the collection. I checked this with breakpoints. I even tried to bind to an ObservableCollection, but there is the same problem.
Binding to another property of my class works (my class implements INotifyPropertyChanged).
Is there anything special with binding to a (ReadOnly)ObservableCollection, that should notify, when its elements changed ( added or removed, to be exact)?
Thanks in advance,
Frank
Edith includes the declaration of the Collection(s):
public class MyClass
{
private ObservableCollection<IServiceItemVMBase> _children;
private ReadOnlyObservableCollection<IServiceItemVMBase> _childrenReadOnly;
public ViewModelBase(IServiceObjectBase serviceObject, IServiceItemVMBase parent)
{
_children = new ObservableCollection<IServiceItemVMBase>();
_childrenReadOnly = new ReadOnlyObservableCollection<IServiceItemVMBase>(_children);
}
public ReadOnlyObservableCollection<IServiceItemVMBase> Children
{
get { return _childrenReadOnly; }
}
}