here is the XAML...
<Canvas Name="myCanvas">
<TextBlock Name="myBlock" FontFamily="Arial Black" FontSize="100" Foreground="Red" Text="R" Height="105" Width="96" Canvas.Left="61" Canvas.Top="80" /
</Canvas>
I have a partial class that extends a userControl.
public partial class Card : UserControl
I also have a test form that uses this control like this,
public formTest()
{
InitializeComponent();
Card1.drawText();
myCanvas.Children.Add(Card1); //myCanvas is defined in XAML
}
Card Card1 = new Card();
How do add an instance of TextBlock to myCanvas when TextBlock is inside my UserControl? So lets say,
public partial class Card : UserControl
{
private TextBlock txtBlock = new TextBlock();
public Card()
{
txtBlock.Text = "Test";
txtBlock.Foreground = brushFill;
}
public void drawText()
{
//uhhh idk
}
}
In general I don't understand how to get anything to display without defining it in the XAML then adding properties via code. Like this I create an instance of TextBlock, give it some properties... then I'm not sure.
Any help is appreciated. I also know I should be using a User Control but I don't know why?
Your UserControl should also have a XAML file associated, and the TextBlock should be inside that XAML.
The other option would be Card : Control (not UserControl) and then you would need a template.
In neither coase can/should you try to add a TextBlock from inside a Control to myCanvas.
Seems you ought to read up on WPF UserControls and Custom Controls.
If you just want to create a simple TextBlock and add it to the canvas, you'll want to do something like this:
TextBlock textBlock = new TextBlock();
textBlock.Text = "Text";
myCanvas.Children.Add(textBlock);
Then you can manipulate everything you have added to the Canvas via methods in Canvas.Children.
Related
I made a sample XAML and C# for WPF below:
XAML :
<Button Name="btn">
<Button.Template>
<ControlTemplate>
<Grid>
<TextBlock Name="textblock1" Text="sampletext1" />
<Grid>
<ControlTemplate>
</Button.Template>
</Button>
C# :
Grid grid = btn.Template.LoadContent() as Grid;
var textblock = grid.FindName("textblock1") as TextBlock;
textblock.Text = "sampletext2";
I was able to retrieve and change the textblock text in code behind but it seems that the UI doesn't update it. May I know how to solve this?
Change your code in any of the events
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.Loaded += MainWindow_Loaded;
}
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
TextBlock textBlockInTemplate = (TextBlock)btn.Template.FindName("textblock1", btn);
textBlockInTemplate.Text = "SampleText2";
}
}
Your code makes a copy of the value of the text block then assign a property named "Text" to the copy's value. You never actually change the text inside the button. Your text block is called textblock1, textblock was initialized from textblock1 but once that is done they aren't linked together.
It's been awhile since i've used WPF but you need to re-assign the text value to the button using something like this :
textblock1.Text = textblock;
or even simpler:
textblock1.Text = "sampletext2";
I want to separate ListBox from MainMenu by creating UserControl. In MainWindow I'm creating, for testing purposes, ObservableCollection (in code-behind) and in MainWindow.xaml I'm trying to pass this Collection through DataContext to UserControl
MainWindow.xaml.cs
ObservableCollection<ListItem> coll = new ObservableCollection<ListItem>()
{
new TextListItem
{
Content = "Some Text", CreationDate = DateTime.Now, VisibleName = "Title"
}
};
MainWindow.xaml
<userControls:ListBoxUserControl DataContext="{Binding Path=coll}"/>
And in ListBoxUserControl.xaml I'm trying to access Collection like that
<ListBox x:Name="listBox" ItemsSource="{Binding}"/>
But it seems not working. How do I pass Collection through DataContext properly?
coll should be a property on the MainWindow class. As I currently read it, it is just a variable which will go out of scope after you left the method (I think the constructor) in which it is defined.
I need to set the font family for the next text to be written in a RichTextBox.
I tried setting that with...
<RichTextBox x:Name="RichTextEditor" MaxWidth="1000" SpellCheck.IsEnabled="True"
FontFamily="{Binding ElementName=TextFontComboBox, Path=SelectedItem}"
FontSize="{Binding ElementName=TextSizeComboBox, Path=SelectedValue}"
Width="Auto" Height="Auto" HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto" />
...but it changed the whole text. I suppose that with the Selection property I can restrict the change to be applied just to the selected area. But how for the next -not yet typed- text?
In order to set the FontFamily based on the cursor position you need to define a custom control with a dependency property that helps insert a new Run section by overriding the OnTextInput method.
I included most of the code, you'll need to modify the namespaces to fit your development environment.
The code uses a ViewModel to manage the available fonts and manage if the font changed.
This code is only a prototype and does not deal with focusing issues between the two controls.
To use this code:
1- Type some text in the RichTectBox.
2- Change the font in the ComboBox.
3- Tab back to the RichTextBox.
4- Type some more text.
Here is the custom RichTextBox control:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
namespace RichTextboxFont.Views
{
public class RichTextBoxCustom : RichTextBox
{
public static readonly DependencyProperty CurrentFontFamilyProperty =
DependencyProperty.Register("CurrentFontFamily",
typeof(FontFamily), typeof
(RichTextBoxCustom),
new FrameworkPropertyMetadata(new FontFamily("Tahoma"),
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
new PropertyChangedCallback(OnCurrentFontChanged)));
public FontFamily CurrentFontFamily
{
get
{
return (FontFamily)GetValue(CurrentFontFamilyProperty);
}
set
{
SetValue(CurrentFontFamilyProperty, value);
}
}
private static void OnCurrentFontChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{}
protected override void OnTextInput(TextCompositionEventArgs e)
{
ViewModels.MainViewModel mwvm = this.DataContext as ViewModels.MainViewModel;
if ((mwvm != null) && (mwvm.FontChanged))
{
TextPointer textPointer = this.CaretPosition.GetInsertionPosition(LogicalDirection.Forward);
Run run = new Run(e.Text, textPointer);
run.FontFamily = this.CurrentFontFamily;
this.CaretPosition = run.ElementEnd;
mwvm.FontChanged = false;
}
else
{
base.OnTextInput(e);
}
}
}
}
Here is the XAML:
<Window x:Class="RichTextboxFont.Views.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:RichTextboxFont.Views"
xmlns:ViewModels="clr-namespace:RichTextboxFont.ViewModels"
Title="Main Window"
Height="400" Width="800">
<DockPanel>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<ComboBox ItemsSource="{Binding Path=Fonts}"
SelectedItem="{Binding Path=SelectedFont, Mode=TwoWay}"/>
<local:RichTextBoxCustom Grid.Row="1"
CurrentFontFamily="{Binding Path=SelectedFont, Mode=TwoWay}"
FontSize="30"/>
</Grid>
</DockPanel>
</Window>
Here is the ViewModel:
If you do not use view models, let me know and I'll add the base class code too; otherwise, google/stackoverflow can help you too.
using System.Collections.ObjectModel;
using System.Windows.Media;
namespace RichTextboxFont.ViewModels
{
public class MainViewModel : ViewModelBase
{
#region Constructor
public MainViewModel()
{
FontFamily f1 = new FontFamily("Georgia");
_fonts.Add(f1);
FontFamily f2 = new FontFamily("Tahoma");
_fonts.Add(f2);
}
private ObservableCollection<FontFamily> _fonts = new ObservableCollection<FontFamily>();
public ObservableCollection<FontFamily> Fonts
{
get
{
return _fonts;
}
set
{
_fonts = value;
OnPropertyChanged("Fonts");
}
}
private FontFamily _selectedFont = new FontFamily("Tahoma");
public FontFamily SelectedFont
{
get
{
return _selectedFont;
}
set
{
_selectedFont = value;
FontChanged = true;
OnPropertyChanged("SelectedFont");
}
}
private bool _fontChanged = false;
public bool FontChanged
{
get
{
return _fontChanged;
}
set
{
_fontChanged = value;
OnPropertyChanged("FontChanged");
}
}
#endregion
}
}
Here is the Window code-behind where I initialise the ViewModel:
using System.Windows;
namespace RichTextboxFont.Views
{
public partial class MainView : Window
{
public MainView()
{
InitializeComponent();
this.DataContext = new ViewModels.MainViewModel();
}
}
}
There's a much easier way to do this: Implement a toolbar for your RichTextBox.
Unlike WinForms, the RichTextBox in WPF doesn't come with a toolbar by default, but it's really easy to create one yourself. The RichTextBox automatically handles many EditingCommands, so it's just a matter of creating a toolbar and some buttons. Microsoft has provided sample code for this at the bottom of the RichTextBox Overview on MSDN.
Unfortunately, those editing commands don't include setting the FontFace property of the selection, though you can create a ComboBox on the toolbar that can trigger the change with an event handler in the codebehind file.
That's the approach taken in this CodePlex article by Gregor Pross: WPF RichTextEditor
The project is commented in German, but the source itself is very clearly written. The codebehind used for his font selector ComboBox looks like this:
private void Fonttype_DropDownClosed(object sender, EventArgs e)
{
string fontName = (string)Fonttype.SelectedItem;
if (fontName != null)
{
RichTextControl.Selection.ApplyPropertyValue(System.Windows.Controls.RichTextBox.FontFamilyProperty, fontName);
RichTextControl.Focus();
}
}
The main reason that people struggle with the FontFace selection is that after the font selection has been made, you must return focus to the RichTextBox. If the user must manually press tab or click into the RichTextBox, a new text selection gets created and you lose the formatting options you've chosen.
One of the answers to this StackOverflow question discusses that problem.
WPF Richtextbox FontFace/FontSize
This isn't exactly a trivial answer.
To do inline text formatting in a Rich TextBox like you want you will have to modify the Document property of the RichTextBox. Very simply, something like this will work
<RichTextBox >
<RichTextBox.Document>
<FlowDocument>
<Paragraph>
<Run>Something</Run>
<Run FontWeight="Bold">Something Else</Run>
</Paragraph>
</FlowDocument>
</RichTextBox.Document>
</RichTextBox>
I think you could create a custom Control that creates a new block element and sets the font properties you need based on the user input.
For example, If the user types something then presses bold. You would want to wrap the previous text in a run and create a new run element setting the FontWeight to bold then the subsequent text will be wrapped in the bolded run.
Again, not a trivial solution but I can't think of any other way to accomplish what you are after.
I'm developing windows phone 8 app. I have a customer UserControl called SelectableButton. The constructor of it is as below:
public SelectableButton()
{
InitializeComponent();
DataContext = this;
}
The xaml of it is like this:
<Grid>
<TextBlock x:Name="ButtonTextBlock"
Text="{Binding SelectableButtonText, Mode=TwoWay}"
SomeOtherCode
/>
...
</Grid>
The SelectableButtonText is a property of this UserControl:
public static readonly DependencyProperty SelectableButtonTextProperty =
DependencyProperty.Register(
"SelectableButtonText", typeof(string),
typeof(SelectableButton),
null
);
Now I use this SelectableButton in a Pivot. I want to bind the SelectableButtonText property to some data. This is the DataTemplate used in a Pivot called PivotTestContent:
<ShareControl:SelectableButton
SelectableButtonText="{Binding question}"
...
>
</ShareControl:SelectableButton>
The question is from the ItemsSource of this Pivot:
PivotTestContent.ItemsSource = quizs;
The quizs is a List<> of WCCQuizText
quizs = new List<WCCQuizText>();
And the question is a property member of WCCQuizText:
public String question
{
get;
set;
}
After all these work, I find that the Binding cant find the property question. It seems that because of this line in the constructor of SelectableButton:
DataContext = this;
The Binding will look for the property question in Class SelectableButton, not from the ItemsSouce. Because if I bind question directly to some TextBlock.Text, it will work. But when I bind it to my UserControl, it can't be found.
So anybody know how to deal with this?
If I do like this, I can show the binding text correctly, the TextBlock is in the Pivot, too.
<TextBlock
Name="TextBlockQuestion"
Text="{Binding question}"
....
>
</TextBlock>
And my Binding:
<ShareControl:SelectableButton
SelectableButtonText="{Binding Text, ElementName=TextBlockQuestion}"
....
>
</ShareControl:SelectableButton>
You are correct. It is caused by DataContext = this. Normally your UserControl would have context set to an instance of WCCQuizText but you are overwriting it with an instance of your UserControl. Try removing that line, give UserControl some name and and change your binding, within UserControl, to something like:
<UserControl x:Name="SomeName" ... >
....
<TextBlock ... Text="{Binding ElementName=SomeName, Path=SelectableButtonText}"
also TextBlock is display control and it will always be one way binding so you can skip Mode=TwoWay
I am developing a screen, and this screen I have a grid. Within this grid, I have a UserControl WebBrowser. I'm using this component to display XML formatted and syntax is highlighted (with color). The text to be displayed is done via Binding, so that the component is a UserControl, as was done for the same modifications accepted Binding (since the original does not accept content via Binding). But I'm experiencing the following problem: when the user resizes the screen of the program at a certain point, the body of the WebBrowser beyond the boundaries of the grid, making the screen is strange at the bottom of the Grid.
I tested with other components, and this problem does not occur.
Behold my UserControl:
<UserControl x: Class = "Geraes.Library.Core.GUI.WPF.Controls.XmlBrowserControl"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns: x = "http://schemas.microsoft.com/winfx/2006/xaml"
x: Name = "thisControl">
<Grid Margin="0,0,0,0" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<WebBrowser Name="WebBrowser" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" />
</ Grid>
</ UserControl>
And here, how I use it:
<ct:XmlBrowserControl XmlDoc="{Binding ContentString}" Grid.Row="1" />
Again, I can't understand why this is happening, since other components works as well inside this grid.
Another thing: we're using WebBrowser because until this moment, it's the best component to show a XML formatted and with syntax-colour. But if you know another one than its better and easy to use, i'm accepting suggestions.
Any help is welcome.
Best regards,
Gustavo.
I was having a similar problem using the webbrowser control, in the end I switched to using awesomium and have found it much nicer to use.
I wanted to size the content of the webbrowser (or webcontrol) to fit content without scroll bars so I could use the scrollbars of the containing element (in my case a grid). I also started with a custom control but then switched to adding the the binding source as an attached property instead and setting the sizes and visibility once the content had loaded. I my case I was using you localing stored html string, but you could use a uri instead
using System;
using System.Windows;
using Awesomium.Windows.Controls;
using Awesomium.Core;
namespace utilities
{
public class WebBrowserHelper {
public static readonly DependencyProperty BodyProperty =
DependencyProperty.RegisterAttached("Body", typeof (string), typeof(WebBrowserHelper), new PropertyMetadata(OnBodyChanged));
public static string GetBody(DependencyObject dependencyObject) {
return (string) dependencyObject.GetValue(BodyProperty);
}
public static void SetBody(DependencyObject dependencyObject, string body) {
dependencyObject.SetValue(BodyProperty, body);
}
private static void ScrollDataReceivedDelegate(object sender, ScrollDataEventArgs e)
{
var webControl = (Awesomium.Windows.Controls.WebControl) sender;
webControl.Height = e.ScrollData.ContentHeight;
webControl.Width = e.ScrollData.ContentWidth;
webControl.Visibility = Visibility.Visible;
}
private static void OnBodyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
var webControl = (Awesomium.Windows.Controls.WebControl) d;
webControl.LoadHTML((string)e.NewValue);
webControl.ScrollDataReceived += new ScrollDataReceivedEventHandler(ScrollDataReceivedDelegate);
webControl.LoadCompleted += delegate {
webControl.RequestScrollData();
};
}
}
}
And the namespaces:
xmlns:utilities="clr-namespace:utilities;assembly=utilities"
xmlns:awesome="clr-namespace:Awesomium.Windows.Controls;assembly=Awesomium.Windows.Controls"
And the xaml:
<awesome:WebControl
HorizontalAlignment="Left"
Width="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Grid}}, Path=ActualWidth}"
Height="1"
utilities:WebBrowserHelper.Body="{Binding html}"
Visibility="Collapsed" />