|
I like it. One question....
In the ShowDialog you have:
DialogResultEx dlgResult = new DialogResultEx();
dlgResult.DialogResult = dialog.DialogResult;
dlgResult.DialogData = viewModel.WhateverData;
How does this method know what object/value on the VM to get? How does 'viewModel.WhateverData' get set from with in this method?
If it's not broken, fix it until it is
|
|
|
|
|
I figured that your model derives from a base type, you can have an object in the model to store any return value (or you could just store the entire view model if you want).
I don't know where you would store the return value in the view model, so I put a placeholder there. You didn't really specify where this would be stored, but I assume you have a field in the model that you can store return data in.
I would put a virtual field in the viewmodel base class (returns null by default) that the derived classes can override to return whatever.
For example:
public abstract class _DialogBaseViewModel
{
public virtual object DialogData { get { return null; } }
}
Then a derived class could write:
public class InputDialogViewModel : _DialogBaseViewModel
{
private string _textData = string.Empty;
public override object DialogData
{
get
{
return _textData;
}
}
}
|
|
|
|
|
OK, I see.. I like the design.
I just coded this:
Service
Same as before....
public static class DialogService
{
private static Dictionary<Type, Type> registry = new Dictionary<Type, Type>();
public static void RegisterDialog(Type dialogType, Type viewModelType)
{
if (!dialogType.IsSubclassOf(typeof(Window)))
{
throw new ArgumentException("The dialogType must be a subclass of type Window.");
}
bool exists = registry.Where(x => x.Key == dialogType).Any();
if (!exists)
{
registry.Add(dialogType, viewModelType);
}
}
public static bool? ShowDialog<TViewModelType>(TViewModelType viewModel) where TViewModelType : _DialogBaseViewModel
{
Type dialogType = registry.Where(x => x.Value == viewModel.GetType()).Select(x => x.Key).FirstOrDefault();
var dialog = (Window)Activator.CreateInstance(dialogType);
dialog.DataContext = viewModel;
dialog.ShowDialog();
return dialog.DialogResult.Value;
}
}
DialogManager
A wrapper class to the Sertvice:
public static class DialogManager
{
static DialogManager()
{
DialogService.RegisterDialog(typeof(SQLConnectionView), typeof(SQLConnectionViewModel));
}
public static string OpenSQLConnectionDialog()
{
string result = string.Empty;
SQLConnectionViewModel vm = new SQLConnectionViewModel();
bool? dialogResult = DialogService.ShowDialog(vm);
if (dialogResult.Value)
{
result = vm.ConnectionString;
}
return result;
}
}
Usage
var connString = DialogManager.OpenSQLConnectionDialog();
By doing it with the wrapper, I can return a value, or the whole VM if I want.
Drawback is that I'd have to specified methods for each dialog I want to open, and possibly more if I wanted different return values;
If it's not broken, fix it until it is
|
|
|
|
|
Ok, I set it up like you suggested. Very nice, and no need for a wrapper class.
Thank you Sir!
If it's not broken, fix it until it is
|
|
|
|
|
Simplicity is a beautiful thing
|
|
|
|
|
Yes it is.
One thing I forgot was the Owner window. So I added an overload.
public static DialogResultEx ShowDialog<TViewModelType>(TViewModelType viewModel) where TViewModelType : _DialogBaseViewModel
{
Type dialogType = registry.Where(x => x.Value == viewModel.GetType()).Select(x => x.Key).FirstOrDefault();
if (dialogType == null)
{
throw new ArgumentException(string.Format("There is no registered dialog corresponding to a view model of type {0}.", viewModel));
}
var dialog = (Window)Activator.CreateInstance(dialogType);
dialog.DataContext = viewModel;
dialog.ShowDialog();
DialogResultEx dlgResult = new DialogResultEx();
dlgResult.DialogResult = dialog.DialogResult;
dlgResult.DialogData = viewModel.DialogData;
return dlgResult;
}
public static DialogResultEx ShowDialog<TViewModelType, TOwnerType>(TViewModelType viewModel, Type ownerType) where TViewModelType : _DialogBaseViewModel
{
Type dialogType = registry.Where(x => x.Value == viewModel.GetType()).Select(x => x.Key).FirstOrDefault();
if (dialogType == null)
{
throw new ArgumentException(string.Format("There is no registered dialog corresponding to a view model of type {0}.", viewModel));
}
var dialog = (Window)Activator.CreateInstance(dialogType);
dialog.DataContext = viewModel;
if (ownerType != null)
{
Window ownerWindow = FindWindow(ownerType);
dialog.Owner = ownerWindow;
}
dialog.ShowDialog();
DialogResultEx dlgResult = new DialogResultEx();
dlgResult.DialogResult = dialog.DialogResult;
dlgResult.DialogData = viewModel.DialogData;
return dlgResult;
}
Usage:
DialogResultEx dialogResult1 = DialogService.ShowDialog<SQLConnectionViewModel>(new SQLConnectionViewModel());
DialogResultEx dialogResult2 = DialogService.ShowDialog<SQLConnectionViewModel, MainWindowView>(new SQLConnectionViewModel(), typeof(MainWindowView));
Given the generics, how do I combine this into one method?
If it's not broken, fix it until it is
|
|
|
|
|
I would overload it...
public static DialogResultEx ShowDialog<TViewModelType>(TViewModelType viewModel, Type ownerType) where TViewModelType : _DialogBaseViewModel
{
Type dialogType = registry.Where(x => x.Value == viewModel.GetType()).Select(x => x.Key).FirstOrDefault();
if (dialogType == null)
{
throw new ArgumentException(string.Format("There is no registered dialog corresponding to a view model of type {0}.", viewModel));
}
var dialog = (Window)Activator.CreateInstance(dialogType);
dialog.DataContext = viewModel;
if (ownerType != null)
{
Window ownerWindow = FindWindow(ownerType);
dialog.Owner = ownerWindow;
}
dialog.ShowDialog();
DialogResultEx dlgResult = new DialogResultEx();
dlgResult.DialogResult = dialog.DialogResult;
dlgResult.DialogData = viewModel.DialogData;
return dlgResult;
}
public static DialogResultEx ShowDialog<TViewModelType>(TViewModelType viewModel) where TViewModelType : _DialogBaseViewModel
{
return ShowDialog<TViewModelType>(viewModel, null);
}
Again, watch those generics and how you use them. You declare the generic TOwnerType but you don't ever use it, so there is no need for it. Using the above you can have both for when you need the owner window and for when you don't, and you have all the code re-use so you only have to maintain in one place.
|
|
|
|
|
OK, I see.. I was trying to set the Owner type in the generic list. Couldn't make it work.
Many thanks!
If it's not broken, fix it until it is
|
|
|
|
|
Thanks for all your help. I appreciate it. It's working great. I added a ShowMessageBox method.
So now that I have this done, I was thinking of writing an article. I know it's been done before, but what do you think?
If it's not broken, fix it until it is
|
|
|
|
|
|
Kevin Marois wrote: I was thinking of writing an article
Excellent - it would save me at least 2 bookmarks and chasing through the thread. I have been looking for a simple dialog service and this seems to meet the requirements without delving too deep (I LIKE simple).
Never underestimate the power of human stupidity
RAH
|
|
|
|
|
Hello,
I found this class in my research but I do not know how to use it. Moreover, it seems to me that the ConvertBack () method is not completely completed.If someone has already used his help will be invaluable for me.
here is the class
[ValueConversion(typeof(byte[]), typeof(ImageSource))]
public class ByteArrayToImageSource : IValueConverter
{
#region Implementation of IValueConverter
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var byteArrayImage = value as byte[];
if (byteArrayImage != null && byteArrayImage.Length > 0)
{
var ms = new MemoryStream(byteArrayImage);
var bitmapImg = new BitmapImage();
bitmapImg.BeginInit();
bitmapImg.StreamSource = ms;
bitmapImg.EndInit();
return bitmapImg;
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
#endregion
}
|
|
|
|
|
This is a converter - it's meant to be used in your XAML to convert from one type to another - in this case, to take a series of bytes and to return an image from it. If you're using this in XAML and you aren't updating the image on the screen, you don't need to worry about the ConvertBack method - it's there to support Binding back from the XAML to the property you're binding to.
|
|
|
|
|
a small code example or a case already studied help me please!
|
|
|
|
|
I am working on this[^] app.
The area in red is a ContentPresenter in the MainWindow. When the user clicks a link in the left Recent Items area, I send a message to the MainWindow to load the view.
That gives me this[^].
I am defining my Views/VM in my resource file:
<DataTemplate DataType="{x:Type vm:HomeViewModel}">
<vw:HomeView/>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:ClientViewModel}">
<vw:ClientView/>
</DataTemplate>
The first question is this...How can the Save button on the MainWindow know that the current view is dirty?
Second, given how I'm designing this... view inside a view in a ContentPresenter, is messaging the right way to communicate?
I'm open to suggestion on my design.
Thanks
If it's not broken, fix it until it is
|
|
|
|
|
I recently discovered CompositeCommand and find it works great for this scenario. It's part of Prism, but I just ripped it out since I don't use Prism.
https://prism.svn.codeplex.com/svn/V1/spikes/AGCompositeApplicationLibrary/AGComposite.Wpf/Commands/CompositeCommand.cs[^]
The toolbar will bind to a static CompositeCommand (i.e. in something like a GlobalCommands.cs) and then a view would attach to it with a RelayCommand. Something like:
GlobalCommands.SaveCommand.RegisterCommand(SaveCommand);
Multiple views can attach to the same command and all get notified when the button is clicked. The one gotcha though is the IActiveAware portion. Your ViewModelBase class needs to be tweaked to properly set the IsActive flags in the commands somehow.
Basically the way the CompositeCommand works is that say vmA and vmB attach... by default, the button will only enable if both return true for canExecute. By setting the IsActive flag on the commands properly, you can make it work in a way where the inactive commands are ignored. For example, if vmA.SaveCommand is not active, only vmB.SaveCommand will get the canexecute/execute calls.
|
|
|
|
|
Just curious, what does your moniker, 'SledgeHammer' refer to?
Could it be this?>>[^]
If it's not broken, fix it until it is
|
|
|
|
|
I would like to add certificate in local machine through Silverlight. I can able to add certificate using X509Store in vb.net windows application.
But how it is possible with Silverlight Application?
|
|
|
|
|
1) usercontrol.xaml.cs
public event RoutedEventHandler CustomClick;
private void btn_Click(object sender, RoutedEventArgs e)
{
if (CustomClick != null)
CustomClick(this, new RoutedEventArgs());
}
2)MainWindow.xaml
<controls:Button CustomClick="btn1_CustomClick" ButtonText="Click Here" Name="btn1" Margin="61,105,93,128"></controls:Button>
3)MainWindow.xaml.cs
private void btn1_CustomClick(object sender, RoutedEventArgs e)
{
MessageBox.Show("Custom control CLicked");
}
Click Event Not working for mybutton
|
|
|
|
|
So have you set breakpoints in the debugger and determined which part of the process isn't happening as you expect?
The CustomClick event in usercontrol.xaml.cs or the btn1_CustomClick in MainWindow.xaml.cs ?
|
|
|
|
|
what is the silver light application? where we can use it..?
|
|
|
|
|
Silverlight is a plugin, similar to Flash, that allows you to run richer web based applications. It's named after my good friend David Silverlight.
|
|
|
|
|
You name dropper you!
Never underestimate the power of human stupidity
RAH
|
|
|
|
|
Oh yes indeedy. Just think, someday I may be telling people I knew the other, other Mycroft Holmes.
|
|
|
|
|
Silverlight is, as Pete said correctly, something like the Microsoft-Version of Flash. However, Microsoft has abandoned the technology, meaning that they are not going to support it for a long time. Therefore Silverlight should be left aside in favor of trqaditional Web technologies, as Javascript, HTML etc. are.
Source[^]
Veni, vidi, caecus
|
|
|
|