我使用自定義WindowsFormsHost
控件在選項卡控件中包裝FastColoredTextbox winforms控件,當用戶通過DataTemplate
點擊新文檔按鈕時,其選項卡動態創建。自定義控件綁定不會更新模型
由於在此SO question中解釋的選項卡控制的限制,我的撤消/重做邏輯保留了每個選項卡的所有選項卡的歷史記錄,導致顯示錯誤的文本。
因此,我決定修改FastColoredTextbox控件以顯示歷史記錄和重做堆棧,並將它們添加到我自定義的WindowsFormsHost包裝器控件中,作爲依賴性屬性,這些屬性通過兩種方式綁定到我的DocumentModel。
XAML:
<TabControl TabStripPlacement="Top" Margin="5" ItemsSource="{Binding Documents}" SelectedItem="{Binding CurrentDocument, Mode=TwoWay}" x:Name="TabDocuments">
<TabControl.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="10" MaxWidth="10" MinWidth="10"/>
<ColumnDefinition Width="10" MaxWidth="10" MinWidth="10"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding Metadata.FileName}"/>
<TextBlock Grid.Column="1" Text="*" Visibility="{Binding IsSaved, Converter={StaticResource VisibilityConverter}}"/>
<Button Grid.Column="2" Width="10" Height="10" MaxWidth="10" MaxHeight="10" MinWidth="10" MinHeight="10" VerticalAlignment="Center" HorizontalAlignment="Right" Command="{Binding CloseDocumentButtonCommand}">
<TextBlock Text="X" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="8" FontWeight="Bold"/>
</Button>
</Grid>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate x:Name="TabDocumentsDataTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border BorderBrush="Black" BorderThickness="1" Grid.Column="0" Margin="5">
<customControls:CodeTextboxHost Text="{Binding Markdown, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" History="{Binding History, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" RedoStack="{Binding RedoStack, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" WordWrap="True" x:Name="CodeTextboxHost"/>
</Border>
<Border BorderBrush="Black" BorderThickness="1" Grid.Column="1" Margin="5">
<wpf:ChromiumWebBrowser Address="{Binding Html, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" x:Name="ChromiumWebBrowser"/>
</Border>
</Grid>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
模型的相關部分:
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;
}
我的問題是,當TextChanged
事件觸發,History
或RedoStack
不更新模型,而Text
完美更新。
我試着添加RelativeSource,因爲這個SO question暗示,但它沒有奏效。
任何幫助/想法,將不勝感激。謝謝。
編輯1:
至於建議我做了所有集合的ObservableCollection,但它沒有做任何改變,因爲該模型再次沒有更新。
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();
}
如果我猜的話,我會說這個問題與您在模型中使用'ObservableCollection'的事實開始的地方做,依賴項屬性中的'Stack'和'LimitedStack'。當這些匹配時,我只有綁定集合的好運氣。我全部使用'ObservableCollection'。 –
我無法弄清楚完整的代碼,但是如果你想明確地調用更新,就有解決方法。嘗試交互觸發TextBox文本更改它將調用帶參數的命令,然後您可以記錄您的更改DS – Ramankingdom
@Ramankingdom我實際上使用它,唯一的區別是,文本框本身是一個winforms控件,我用它包裝'WindowsFormsHost'。我使用內部文本框的TextChanged事件來更新文本,歷史記錄和重做堆棧(可以在'_innerTextbox_TextChanged'方法中看到)。但是,問題只是文本更新,其餘部分不會更新並存儲回模型中。 –