C# 自定义控件绑定不';不要更新模型
我正在使用自定义的C# 自定义控件绑定不';不要更新模型,c#,wpf,data-binding,dependency-properties,C#,Wpf,Data Binding,Dependency Properties,我正在使用自定义的WindowsFormsHost控件将winforms控件包装到选项卡控件中,当用户通过DataTemplate点击“新建文档”按钮时,会动态创建选项卡 由于本文中解释的选项卡控件的限制,我的撤消/重做逻辑保留了每个选项卡的所有选项卡的历史记录,这导致显示错误的文本 因此,我决定修改FastColoredTextbox控件以公开历史记录和重做堆栈,并将它们作为依赖项属性添加到自定义WindowsFormsHost包装器控件中,该属性以两种方式绑定到我的DocumentModel
WindowsFormsHost
控件将winforms控件包装到选项卡控件中,当用户通过DataTemplate
点击“新建文档”按钮时,会动态创建选项卡
由于本文中解释的选项卡控件的限制,我的撤消/重做逻辑保留了每个选项卡的所有选项卡的历史记录,这导致显示错误的文本
因此,我决定修改FastColoredTextbox控件以公开历史记录和重做堆栈,并将它们作为依赖项属性添加到自定义WindowsFormsHost包装器控件中,该属性以两种方式绑定到我的DocumentModel
XAML:
我可以通过修改自定义控件代码使UI更改模型,如下所示:
public static readonly DependencyProperty HistoryProperty = DependencyProperty.Register("History", typeof(IEnumerable<UndoableCommand>), typeof(CodeTextboxHost), new FrameworkPropertyMetadata(new ObservableCollection<UndoableCommand>(), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(
(d, e) =>
{
var textBoxHost = d as CodeTextboxHost;
if (textBoxHost != null && textBoxHost._innerTextbox != null)
{
var history = textBoxHost.GetValue(e.Property) as ObservableCollection<UndoableCommand>;
if (history != null)
{
textBoxHost._innerTextbox.TextSource.Manager.History = history.ToLimitedStack(200);
textBoxHost._innerTextbox.OnUndoRedoStateChanged();
}
else
{
textBoxHost._innerTextbox.ClearUndo();
}
}
}), null));
public static readonly DependencyProperty RedoStackProperty = DependencyProperty.Register("RedoStack", typeof(IEnumerable<UndoableCommand>), typeof(CodeTextboxHost), new FrameworkPropertyMetadata(new ObservableCollection<UndoableCommand>(), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(
(d, e) =>
{
var textBoxHost = d as CodeTextboxHost;
if (textBoxHost != null && textBoxHost._innerTextbox != null)
{
var redoStack = textBoxHost.GetValue(e.Property) as ObservableCollection<UndoableCommand>;
if (redoStack != null)
{
textBoxHost._innerTextbox.TextSource.Manager.RedoStack = redoStack.ToStack();
textBoxHost._innerTextbox.OnUndoRedoStateChanged();
}
else
{
textBoxHost._innerTextbox.ClearUndo();
}
}
}), null));
public ObservableCollection<UndoableCommand> History
{
get { return (ObservableCollection<UndoableCommand>) GetValue(HistoryProperty);}
set { SetCurrentValue(HistoryProperty, new ObservableCollection<UndoableCommand>(value));}
}
public ObservableCollection<UndoableCommand> RedoStack
{
get { return (ObservableCollection<UndoableCommand>) GetValue(RedoStackProperty); }
set { SetCurrentValue(RedoStackProperty, new ObservableCollection<UndoableCommand>(value));}
}
public static readonly dependencProperty HistoryProperty=dependencProperty.Register(“History”、typeof(IEnumerable)、typeof(CodeTextboxHost)、new FrameworkPropertyMetadata(new ObservableCollection()、FrameworkPropertyMetadata Options.bindstwoway默认情况下,new PropertyChangedCallback(
(d,e)=>
{
var textBoxHost=d作为CodeTextboxHost;
if(textBoxHost!=null&&textBoxHost.\u innerTextbox!=null)
{
var history=textBoxHost.GetValue(e.Property)作为ObservableCollection;
if(历史!=null)
{
textBoxHost.\u innerTextbox.TextSource.Manager.History=History.ToLimitedStack(200);
textBoxHost._innerTextbox.OnUndoRedoStateChanged();
}
其他的
{
textBoxHost._innerTextbox.ClearUndo();
}
}
}),空);
public static readonly dependencProperty RedoStackProperty=dependencProperty.Register(“RedoStack”、typeof(IEnumerable)、typeof(CodeTextboxHost)、new FrameworkPropertyMetadata(new ObservableCollection()、FrameworkPropertyMetadataOptions.Bindstwoway默认情况下,new PropertyChangedCallback(
(d,e)=>
{
var textBoxHost=d作为CodeTextboxHost;
if(textBoxHost!=null&&textBoxHost.\u innerTextbox!=null)
{
var redoStack=textBoxHost.GetValue(e.Property)作为ObservableCollection;
if(redoStack!=null)
{
textBoxHost._innerTextbox.TextSource.Manager.RedoStack=RedoStack.ToStack();
textBoxHost._innerTextbox.OnUndoRedoStateChanged();
}
其他的
{
textBoxHost._innerTextbox.ClearUndo();
}
}
}),空);
公众可观察的收集历史
{
get{return(ObservableCollection)GetValue(HistoryProperty);}
set{SetCurrentValue(HistoryProperty,新的ObservableCollection(value));}
}
公共可观测收集重做堆栈
{
获取{return(observeCollection)GetValue(RedoStackProperty);}
set{SetCurrentValue(RedoStackProperty,新的observeCollection(value));}
}
因此,与设置值相比,我使用
History
上的SetCurrentValue
和RedoStack
使UI正确更新模型。使用INotifyPropertyChanged
接口并实现OnPropertyChanged
方法,如果我不得不猜测,将该方法放在您想更新接口的位置,我想说的是,问题开始于这样一个事实:您在模型中使用了ObservableCollection
,在依赖属性中使用了Stack
和LimitedStack
。我只有在这些匹配的时候才有装订收藏的好运气。我总共使用了ObservableCollection
。我无法理解完整的代码,但如果您想显式调用更新,则有一些解决方法。在文本框上尝试交互触发器文本更改它将调用一个带有参数的命令,然后您可以记录您的更改DS@Ramankingdom我实际上使用它,唯一的区别是Textbox本身是一个winforms控件,我用WindowsFormsHost
包装它。我使用内部文本框的TextChanged
事件来更新文本、历史记录和重做堆栈(可以在\u innerTextbox\u TextChanged
方法中看到)。但是问题只是文本更新,其余的不会更新并存储回模型。@maykanat是调用没有传播到堆栈正在更新的代码?@Ramankingdom例如,我在DocumentModel
属性更新的DocumentText
中放置了一个断点。触发TextChanged
时,CodeTextboxHost
的Text
属性将更新,在DocumentModel
中达到断点,并且DocumentText
属性实际上在DocumentModel
中更新。但是,当我对RedoStack
和History
执行相同操作时,当触发TextChanged
时,模型端不会发生任何事情,就好像用户界面没有通知DocumentModel
一样。因此,从模型到UI的绑定是有效的,但对于可观察集合
,情况并非如此。也许一个指向更好答案的链接会有所帮助:我不想更新UI,当前的数据绑定可以从模型到UI很好地工作。问题是,当我在可观察集合的UI中进行更新时,它不会更新模型的可观察集合。
public ObservableCollection<UndoableCommand> History
{
get { return _history; }
set
{
_history = value;
OnPropertyChanged();
}
}
public ObservableCollection<UndoableCommand> RedoStack
{
get { return _redoStack; }
set
{
_redoStack = value;
OnPropertyChanged();
}
}
public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(CodeTextboxHost), new PropertyMetadata("", new PropertyChangedCallback(
(d, e) =>
{
var textBoxHost = d as CodeTextboxHost;
if (textBoxHost != null && textBoxHost._innerTextbox != null)
{
textBoxHost._innerTextbox.Text = textBoxHost.GetValue(e.Property) as string;
}
}), null));
public static readonly DependencyProperty HistoryProperty = DependencyProperty.Register("History", typeof(LimitedStack<UndoableCommand>), typeof(CodeTextboxHost), new PropertyMetadata(new LimitedStack<UndoableCommand>(200), new PropertyChangedCallback(
(d, e) =>
{
var textBoxHost = d as CodeTextboxHost;
if (textBoxHost != null && textBoxHost._innerTextbox != null)
{
var history = textBoxHost.GetValue(e.Property) as LimitedStack<UndoableCommand>;
if (history != null)
{
textBoxHost._innerTextbox.TextSource.Manager.History = history;
textBoxHost._innerTextbox.OnUndoRedoStateChanged();
}
else
{
textBoxHost._innerTextbox.ClearUndo();
}
}
}), null));
public static readonly DependencyProperty RedoStackProperty = DependencyProperty.Register("RedoStack", typeof(Stack<UndoableCommand>), typeof(CodeTextboxHost), new PropertyMetadata(new Stack<UndoableCommand>(), new PropertyChangedCallback(
(d, e) =>
{
var textBoxHost = d as CodeTextboxHost;
if (textBoxHost != null && textBoxHost._innerTextbox != null)
{
var redoStack = textBoxHost.GetValue(e.Property) as Stack<UndoableCommand>;
if (redoStack != null)
{
textBoxHost._innerTextbox.TextSource.Manager.RedoStack = redoStack;
textBoxHost._innerTextbox.OnUndoRedoStateChanged();
}
else
{
textBoxHost._innerTextbox.ClearUndo();
}
}
}), null));
public LimitedStack<UndoableCommand> History
{
get { return (LimitedStack<UndoableCommand>) GetValue(HistoryProperty);}
set { SetValue(HistoryProperty, value);}
}
public Stack<UndoableCommand> RedoStack
{
get { return (Stack<UndoableCommand>) GetValue(RedoStackProperty); }
set { SetValue(RedoStackProperty, value);}
}
public CodeTextboxHost()
{
Child = _innerTextbox;
_innerTextbox.Language = FastColoredTextBoxNS.Language.Custom;
_innerTextbox.DescriptionFile = AppDomain.CurrentDomain.BaseDirectory + "SyntaxConfig\\MarkdownSyntaxHighlighting.xml";
_innerTextbox.HighlightingRangeType = HighlightingRangeType.AllTextRange;
_innerTextbox.TextChanged += _innerTextbox_TextChanged;
}
private void _innerTextbox_TextChanged(object sender, TextChangedEventArgs e)
{
Text = _innerTextbox.Text;
History = _innerTextbox.TextSource.Manager.History;
RedoStack = _innerTextbox.TextSource.Manager.RedoStack;
}
public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(CodeTextboxHost), new PropertyMetadata("", new PropertyChangedCallback(
(d, e) =>
{
var textBoxHost = d as CodeTextboxHost;
if (textBoxHost != null && textBoxHost._innerTextbox != null)
{
textBoxHost._innerTextbox.Text = textBoxHost.GetValue(e.Property) as string;
}
}), null));
public static readonly DependencyProperty HistoryProperty = DependencyProperty.Register("History", typeof(ObservableCollection<UndoableCommand>), typeof(CodeTextboxHost), new PropertyMetadata(new ObservableCollection<UndoableCommand>(), new PropertyChangedCallback(
(d, e) =>
{
var textBoxHost = d as CodeTextboxHost;
if (textBoxHost != null && textBoxHost._innerTextbox != null)
{
var history = textBoxHost.GetValue(e.Property) as ObservableCollection<UndoableCommand>;
if (history != null)
{
textBoxHost._innerTextbox.TextSource.Manager.History = history.ToLimitedStack(200);
textBoxHost._innerTextbox.OnUndoRedoStateChanged();
}
else
{
textBoxHost._innerTextbox.ClearUndo();
}
}
}), null));
public static readonly DependencyProperty RedoStackProperty = DependencyProperty.Register("RedoStack", typeof(ObservableCollection<UndoableCommand>), typeof(CodeTextboxHost), new PropertyMetadata(new ObservableCollection<UndoableCommand>(), new PropertyChangedCallback(
(d, e) =>
{
var textBoxHost = d as CodeTextboxHost;
if (textBoxHost != null && textBoxHost._innerTextbox != null)
{
var redoStack = textBoxHost.GetValue(e.Property) as ObservableCollection<UndoableCommand>;
if (redoStack != null)
{
textBoxHost._innerTextbox.TextSource.Manager.RedoStack = redoStack.ToStack();
textBoxHost._innerTextbox.OnUndoRedoStateChanged();
}
else
{
textBoxHost._innerTextbox.ClearUndo();
}
}
}), null));
public ObservableCollection<UndoableCommand> History
{
get { return (ObservableCollection<UndoableCommand>) GetValue(HistoryProperty);}
set { SetValue(HistoryProperty, value);}
}
public ObservableCollection<UndoableCommand> RedoStack
{
get { return (ObservableCollection<UndoableCommand>) GetValue(RedoStackProperty); }
set { SetValue(RedoStackProperty, value);}
}
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public bool WordWrap
{
get { return (bool)GetValue(WordWrapProperty); }
set { SetValue(WordWrapProperty, value); }
}
public CodeTextboxHost()
{
Child = _innerTextbox;
_innerTextbox.Language = FastColoredTextBoxNS.Language.Custom;
_innerTextbox.DescriptionFile = AppDomain.CurrentDomain.BaseDirectory + "SyntaxConfig\\MarkdownSyntaxHighlighting.xml";
_innerTextbox.HighlightingRangeType = HighlightingRangeType.AllTextRange;
_innerTextbox.TextChanged += _innerTextbox_TextChanged;
}
private void _innerTextbox_TextChanged(object sender, TextChangedEventArgs e)
{
Text = _innerTextbox.Text;
History = _innerTextbox.TextSource.Manager.History.ToOveObservableCollection();
RedoStack = _innerTextbox.TextSource.Manager.RedoStack.ToObservableCollection();
}
public static readonly DependencyProperty HistoryProperty = DependencyProperty.Register("History", typeof(IEnumerable<UndoableCommand>), typeof(CodeTextboxHost), new FrameworkPropertyMetadata(new ObservableCollection<UndoableCommand>(), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(
(d, e) =>
{
var textBoxHost = d as CodeTextboxHost;
if (textBoxHost != null && textBoxHost._innerTextbox != null)
{
var history = textBoxHost.GetValue(e.Property) as ObservableCollection<UndoableCommand>;
if (history != null)
{
textBoxHost._innerTextbox.TextSource.Manager.History = history.ToLimitedStack(200);
textBoxHost._innerTextbox.OnUndoRedoStateChanged();
}
else
{
textBoxHost._innerTextbox.ClearUndo();
}
}
}), null));
public static readonly DependencyProperty RedoStackProperty = DependencyProperty.Register("RedoStack", typeof(IEnumerable<UndoableCommand>), typeof(CodeTextboxHost), new FrameworkPropertyMetadata(new ObservableCollection<UndoableCommand>(), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, new PropertyChangedCallback(
(d, e) =>
{
var textBoxHost = d as CodeTextboxHost;
if (textBoxHost != null && textBoxHost._innerTextbox != null)
{
var redoStack = textBoxHost.GetValue(e.Property) as ObservableCollection<UndoableCommand>;
if (redoStack != null)
{
textBoxHost._innerTextbox.TextSource.Manager.RedoStack = redoStack.ToStack();
textBoxHost._innerTextbox.OnUndoRedoStateChanged();
}
else
{
textBoxHost._innerTextbox.ClearUndo();
}
}
}), null));
public ObservableCollection<UndoableCommand> History
{
get { return (ObservableCollection<UndoableCommand>) GetValue(HistoryProperty);}
set { SetCurrentValue(HistoryProperty, new ObservableCollection<UndoableCommand>(value));}
}
public ObservableCollection<UndoableCommand> RedoStack
{
get { return (ObservableCollection<UndoableCommand>) GetValue(RedoStackProperty); }
set { SetCurrentValue(RedoStackProperty, new ObservableCollection<UndoableCommand>(value));}
}