Caliburn Micro: querying view-specific data from the VM
I'm completely new to CM and also to learn it I'm migrating an application from MVVM light to Caliburn Micro. In my original cod开发者_如何学Pythone, I had a VM which responds to some UI actions (via commands) to replace some text into a string. The position is given by the view, using the textbox selection.
So the VM has (1) a bound string property representing the textbox's text, (2) another bound string property to represent the new text to be added, and (3) needs to know selection start and length in order to replace the right portion of text with the new one.
In my original code, I had a custom DialogMessage-derived object sent in the VM command implementation with a couple of properties for selection data: when the command was issued, the message was sent, and the view received it and filled it with its textbox selection start and length; then the VM was called back and could use these data.
Which would be the best way of implementing this in CM? I'd prefer the VM to remain agnostic of the view, so I don't like too much the idea of accessing the view from it. I'd rather opt for a "message"-based mechanism like the above, but I'm not sure how I can implement it in CM: I would probably look at IResult, but most of the samples I find are related to coroutines and I'm not sure how to relate the void ReplaceText() method of the VM to the view code behind.
Could anyone point me in the right direction, and/or to some code samples about dialog-like interactions between VM 'command' methods and view? Thanks!
I'd probably look at the IResult option. You'll have access to the view so code that you would have had in the code behind can be in your Result and not in your VM.
Here is code from a ShowDialog result. I believe I grabbed it from the CM discussion group. Search the discussion group for ShowDialog for more examples. The GameLibrary sample that comes with CM also has some.
public class ShowDialog : IResult
{
private readonly Type _screenType;
private readonly string _name;
[Import]
public IWindowManager WindowManager { get; set; }
public ShowDialog(string name)
{
_name = name;
}
public ShowDialog(Type screenType)
{
_screenType = screenType;
}
public void Execute(ActionExecutionContext context)
{
var screen = !string.IsNullOrEmpty(_name)
? IoC.Get<object>(_name)
: IoC.GetInstance(_screenType, null);
Dialog = screen;
WindowManager.ShowDialog(screen);
var deactivated = screen as IDeactivate;
if (deactivated == null)
Completed(this, new ResultCompletionEventArgs());
else
{
deactivated.Deactivated += (o, e) =>
{
if (e.WasClosed)
{
Completed(this, new ResultCompletionEventArgs());
}
};
}
}
public object Dialog { get; private set; }
public event EventHandler<ResultCompletionEventArgs> Completed = delegate { };
public static ShowDialog Of<T>()
{
return new ShowDialog(typeof (T));
}
}
edit: If you extend TextBox you can bind SelectedText.
public class TextBoxEx : TextBox
{
public static readonly DependencyProperty SelectedTextProperty = DependencyProperty.Register("SelectedText", typeof(string), typeof(TextBoxEx), new PropertyMetadata("oa"));
public TextBoxEx()
{
SelectionChanged += UpdateDependencyProperty;
}
private void UpdateDependencyProperty(object sender, RoutedEventArgs e)
{
SelectedText = base.SelectedText;
}
public new string SelectedText
{
get { return GetValue(SelectedTextProperty).ToString(); }
set { SetValue(SelectedTextProperty, base.SelectedText); }
}
}
then:
<SLTest:TextBoxEx x:Name="MyTextBox2"
Grid.Row="1"
Width="200"
SelectedText="{Binding SelectedText, Mode=TwoWay}"
Text="This is some text." />
精彩评论