I'm trying to load RTF text from database and display it into datatemplate of custom RichTextBox .
I would like to get the text with style , with code the matter is simple but when I'm trying to use <GridViewDataColumn.CellTemplate> <GridViewDataColumn.CellTemplate/> , it got difficult
Xaml code:
<telerik:GridViewDataColumn DataMemberBinding="{Binding document}" Width="*" x:Name="Description" IsReadOnly="True">
<telerik:GridViewDataColumn.CellTemplate>
<DataTemplate >
<local:UC_Description x:Name="richtext">
</local:UC_Description>
</DataTemplate>
</telerik:GridViewDataColumn.CellTemplate>
C# code:
List= new Controller().GetAll();
foreach (Model item in List)
{
RtfFormatProvider provider = new RtfFormatProvider();
DocumentFormatProvidersManager.RegisterFormatProvider(provider);
byte[] byteArray = Encoding.ASCII.GetBytes(item.Description);
document = provider.Import(byteArray);
FlowDocument flow = new FlowDocument();
}
GridViewList.ItemsSource = null;
GridViewList.ItemsSource = List;
this.DataContext = this;
}
public RadDocument ImportXaml(string content)
{
RtfFormatProvider provider = new RtfFormatProvider();
return provider.Import(text);
}
public string RtfToPlainText(string rtf)
{
byte[] byteArray = Encoding.ASCII.GetBytes(rtf);
var flowDocument = new FlowDocument();
TextRange tr;
using (MemoryStream ms = new MemoryStream(byteArray))
{
tr = new TextRange(flowDocument.ContentStart, flowDocument.ContentEnd);
tr.Load(ms, DataFormats.Rtf);
}
return tr.Text;
}
How can I display text from RTF content in a data template?
A template is a template and there is no UC_Description or RichTextBox until it has been applied at runtime.
What you could do is to handle the Loaded event for the UserControl and then set the Document property of the RichTextBox to your document:
XAML:
<telerik:GridViewDataColumn.CellTemplate>
<DataTemplate >
<local:UC_Description Loaded="OnLoaded" />
</DataTemplate>
</telerik:GridViewDataColumn.CellTemplate>
Code:
private void OnLoaded(object sender, RoutedEventArgs e)
{
UC_Description uc = (UC_Description)sender;
uc.richTextBox.Document = ...;
}
Is there a way to implement an image within a TextBlock rather than outside of it? Android has a feature called SpaanableStringBuilder which allows the user to create text with different appearances. Does UWP have something similar?
MyTextBlock.Text = "Google" + ? + "icon";
As Raymond said, in UWP, RichTextBlock is needed for image and text mixing.
With Xaml
<RichTextBlock>
<Paragraph>
<Run Text="Something..."/>
<InlineUIContainer>
<Image Source="your_image_url" Width="20" Height="20"/>
</InlineUIContainer>
<Run Text="Something..."/>
</Paragraph>
</RichTextBlock>
With Code
var richTextBlock = new RichTextBlock();
var para = new Paragraph();
para.Inlines.Add(new Run() { Text = "Something..." });
var imgContainer = new InlineUIContainer();
var img = new Image();
img.Source = new BitmapImage(new Uri("your_image_url"));
imgContainer.Child = img;
para.Inlines.Add(imgContainer);
para.Inlines.Add(new Run() { Text = "Something..." });
richTextBlock.Blocks.Add(para);
Or you could write it this way, which more closely mirrors the XAML.
var richTextBlock = new RichTextBlock()
{
Blocks = {
new Paragraph {
Inlines = {
new Run { Text = "Something" },
new InlineUIContainer {
Child = new Image {
Source = new BitmapImage(new Uri("your_image_url"))
}
},
new Run { Text = "Something..."}
}
}
}
};
I have short xaml code :
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Category}"></TextBlock>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox Text="{Binding Category}" KeyUp="TextBox_KeyUp"></TextBox>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
But I dont know how to convert it on c#. I did that: but it dont work, and dont know how add Event to TextBox:
Edit: dont throw exception, but still dont work. Without event.
var a = new DataGridTemplateColumn() { Header = "Kategoria", Width = new DataGridLength(1, DataGridLengthUnitType.Star) };
var aa = new DataTemplate();
aa.Resources.Add(1, new TextBlock() { Text = new Binding("Category").ToString() });
a.CellTemplate = aa;
var aaa = new DataTemplate();
aaa.Resources.Add(2, new System.Windows.Controls.TextBox() { Text = new Binding("Category").ToString() });
a.CellEditingTemplate = aaa;
ProjectDataGrid.Columns.Add(a);
ProjectDataGrid.Columns.Add(new DataGridTextColumn() { Header = "Mnemonik", Binding = new Binding("Mnemoniese"), Width = new DataGridLength(1, DataGridLengthUnitType.Star) });
I think it might be helpful. I just convert your XAML markup in C# code step by step.
DataGridTemplateColumn templateColumn = new DataGridTemplateColumn
{
CellTemplate = new DataTemplate
{
DataType = typeof(TextBlock)
},
CellEditingTemplate = new DataTemplate
{
DataType = typeof(TextBox)
}
};
FrameworkElementFactory CategoryBlock = new FrameworkElementFactory(typeof(TextBlock));
CategoryBlock.SetBinding(TextBlock.TextProperty, new Binding("Category"));
templateColumn.CellTemplate.VisualTree = CategoryBlock;
FrameworkElementFactory CategoryTextBox = new FrameworkElementFactory(typeof(TextBox));
CategoryTextBox.SetBinding(TextBox.TextProperty, new Binding("Category"));
CategoryTextBox.AddHandler(KeyUpEvent, new KeyEventHandler(TextBox_KeyUp));
templateColumn.CellEditingTemplate.VisualTree = CategoryTextBox;
ProjectDataGrid.Columns.Add(templateColumn);
I need to bind array of object Images to WrapPanel.
I have declared objects in main class constructor:
public MainWindow()
{
InitializeComponent();
private Masina[] _masina = new Masina[12];
DataContext = new
{
data1 = _masina
};
}
My Class Masina haves few variables inside it, but I want to bind just Image:
public class Masina
{
public Image masina_pav = new Image();
public bool r_mas;
public string s_mas;
public Masina()
{
byte[] buffer = File.ReadAllBytes("teksturos/masinos/red/top.png");
MemoryStream memoryStream = new MemoryStream(buffer);
BitmapImage bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.DecodePixelWidth = 100;
bitmap.DecodePixelHeight = 200;
bitmap.StreamSource = memoryStream;
bitmap.EndInit();
bitmap.Freeze();
masina_pav.Source = bitmap;
Canvas.SetLeft(masina_pav, 100);
Canvas.SetTop(masina_pav, 200);
}
}
I have tried this XAML code:
<WrapPanel Name="zem" Height="1000" Width="1108" >
<ItemsControl ItemsSource="{Binding data1}" DisplayMemberPath="masina_pav">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Name="masinu_sarasas" HorizontalAlignment="Center" IsItemsHost="True" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</WrapPanel >
For now program starts but don't show me any Image (should be 12 of them). Can someone help me to figure it out ?
Image is a view class that should not be used in view models. Instead, your class should provide a public property of type ImageSource. Note that it's a property, not a field as you had declared it. This is necessary because WPF data binding only works with public properties.
public class Masina
{
public ImageSource MasinaPav { get; private set; }
...
public Masina()
{
using (var fileStream = new FileStream(
"teksturos/masinos/red/top.png",
FileMode.Open, FileAccess.Read, FileShare.Read))
{
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.DecodePixelWidth = 100;
bitmap.DecodePixelHeight = 200;
bitmap.StreamSource = fileStream;
bitmap.EndInit();
bitmap.Freeze();
MasinaPav = bitmap;
}
}
}
Now your ItemsControl would have an ItemTemplate with an Image control that is bound to the view model property:
<ItemsControl ItemsSource="{Binding data1}">
...
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Source="{Binding MasinaPav}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Besides that, you should be careful with setting a BitmapImage's DecodePixelWidth and DecodePixelHeight at the same time, because it may spoil the bitmap's aspect ratio.
I have a TreeView with several layers in it. Each item is populated with an ObservableCollection of MenuFlyoutItem dependent on its object type created dynamically at runtime. It's important to note this is in a Windows 10 Universal App, so any solutions or recommendations need to be relevant to them.
The TreeView objects are created like so:
public TreeViewItemModel(object thing)
{
MenuItems.Clear();
if (thing.GetType() == typeof (Space))
{
var space = (Space)thing;
var parentName = string.Empty;
if (space.Parent != null)
{
parentName = space.Parent.Name;
}
Name = space.Name;
ParentName = parentName;
Id = space.Id;
var addDeviceMenuItem = new MenuFlyoutItem { Name = "AddDevice", Text = "Add Device"};
var addSensorMenuItem = new MenuFlyoutItem { Name = "AddSensor", Text = "Add Sensor" };
var addSpaceMenuItem = new MenuFlyoutItem { Name = "AddSpace", Text="Add Space"};
var updateMenuItem = new MenuFlyoutItem { Name = "UpdateSpaceInfo", Text = "Update Space Info" };
var deleteMenuItem = new MenuFlyoutItem { Name = "DeleteSpace", Text = "Delete Space" };
var items = new ObservableCollection<MenuFlyoutItem> {addDeviceMenuItem, addSensorMenuItem,addSpaceMenuItem, updateMenuItem, deleteMenuItem};
MenuItems = items;
Children = new ObservableCollection<TreeViewItemModel>(space.Children.Select(s => new TreeViewItemModel(s)).Union(space.Devices.Select(d => new TreeViewItemModel(d)).Union(space.Sensors.Select(sensor => new TreeViewItemModel(sensor)))));
}
else if (thing.GetType() == typeof (Device))
{
var device = (Device) thing;
var parentName = device.Space.Name;
Name = device.Name;
ParentName = parentName;
Id = device.Id;
var addMenuItem = new MenuFlyoutItem { Name = "AddSensor", Text = "Add Sensor" };
var updateMenuItem = new MenuFlyoutItem { Name = "UpdateDeviceInfo", Text = "Update Device Info" };
var deleteMenuItem = new MenuFlyoutItem { Name = "DeleteDevice", Text = "Delete Device" };
var items = new ObservableCollection<MenuFlyoutItem> { addMenuItem, updateMenuItem, deleteMenuItem };
MenuItems = items;
Children = new ObservableCollection<TreeViewItemModel>(device.Sensors.Select(s => new TreeViewItemModel(s)));
}
else if (thing.GetType() == typeof(Sensor))
{
var sensor = (Sensor) thing;
var space = sensor.Space.Name ?? string.Empty;
var device = sensor.Device;
ParentName = device == null ? "No Matching Device" : device.Name;
Name = sensor.Id.ToString();
Id = sensor.Id;
ParentName = space;
var updateMenuItem = new MenuFlyoutItem { Name = "UpdateSensorInfo", Text = "Update Sensor Info" };
var deleteMenuItem = new MenuFlyoutItem { Name = "DeleteSensor", Text = "Delete Sensor" };
var items = new ObservableCollection<MenuFlyoutItem> {updateMenuItem, deleteMenuItem};
MenuItems = items;
Children = null;
}
}
My TreeView in xaml looks like this:
<controls:TreeView x:Name="TreeViewList" Grid.Row="0" Margin="5" ItemsSource="{Binding TreeSpaces}">
<controls:TreeView.ItemTemplate>
<DataTemplate>
<data:DataTemplateExtensions.Hierarchy>
<data:HierarchicalDataTemplate ItemsSource="{Binding Children}"/>
</data:DataTemplateExtensions.Hierarchy>
<Button x:Name="TreeButton" Content="{Binding Name}" BorderThickness="0" BorderBrush="Transparent" Background="Transparent">
<Button.Flyout>
<Flyout common:BindableFlyout.ItemsSource="{Binding MenuItems}">
<common:BindableFlyout.ItemTemplate>
<DataTemplate>
<MenuFlyoutItem Text="{Binding Text}"/>
</DataTemplate>
</common:BindableFlyout.ItemTemplate>
</Flyout>
</Button.Flyout>
</Button>
</DataTemplate>
</controls:TreeView.ItemTemplate>
</controls:TreeView>
I can't seem to get any form of event handling to trigger on the MenuFlyoutItem to work.
Initially I tried <MenuFlyoutItem Name={Binding Name} Text={Binding Text} view:EventHandlers.Attach="Click"/> This works off a custom MVVM implementation to attach events to ViewModel handlers. Behind the scenes, our attaching mechanism takes the Name of the object and associates with a Click so it would look like this in the View Model if the name were say SaveButton: public void SaveButton_Click(object sender, RoutedEventArgs e). Now, I've normally never had an issue with this, but I thought the problem might have stemmed from trying to use DataBinding for the MenuFlyoutItem's Name rather than the traditional x:Name="blah blah"; however, trying that did not work either. I thought maybe this could be because it was a MenuFlyoutItem rather than a button per say, so I tried changing it to a <Button/> with all the respective stuff, and that didn't work either. So, I went back to MenuFlyoutItem and tried to use the Command property instead. i.e. Command="{Binding MenuItemSelected}". Then in my ViewModel I have the following:
public RelayCommand<object> MenuItemSelected { get; internal set; }
public TreeViewPageVM()
{
MenuItemSelected = new RelayCommand<object>(TestAction);
}
private void TestAction(object sender)
{
}
That didn't work either... So, as much as I want to use MVVM, I resulted to trying code behind by using the traditional <MenuFlyoutItem x:Name="MenuItem" Text="{Binding Text} Click="MenuItem_Clicked" and a corresponding private void MenuItem_Clicked(object sender, RoutedEventArgs e) handler. Much to my surprise this didn't work either. So, I'm not sure what's causing what seems like a suppression on my MenuFlyoutItem's ability to generate events, but some help on this would be appreciated.
Ideally whether it's a click event or command event, I'd like to handle it in my ViewModel, and I'd want the command or click event to be able to grab the Content on the button that generated the Flyout Menu (I'll need that during post processing of the event) as well as the Text from the MenuFlyoutItem that was clicked.
Just in case there needs to be any additional clarity:
I would have objects in the tree like so
----Object1
--------SubObject
and if I click on SubObject (which in this case is a Button that has a flyout attached) a flyout menu with options like: Add, Update, Delete show up. When I click/tap on Add for example, I need my end event handler or command to be aware of SubObject (specifically it's Content because it's a button) and the MenuFlyoutItem that was clicked (specifically the Text property so I know whether I need to add, update, or delete).
The quick and correct answer given above (i.e.adding the Command in the same code where you create the MenuFlyoutItem) leads to the fact that your code violates the MVVM pattern, because you create View's Controls in the ViewModel, so a better solution would be
1) implementing a ViewModel for the Flyout
public class DeviceViewModel
{
public string Name { get; set; }
internal int treeNum;
private DelegateCommand flyoutCommand;
public ICommand FlyoutCommand
{
get
{
if (flyoutCommand == null)
{
flyoutCommand = new DelegateCommand((parameter) => FlyoutLogic(), (parameter) => CanFlyout());
}
return flyoutCommand;
}
}
private bool CanFlyout()
{
return true;
}
private void FlyoutLogic()
{
Debug.WriteLine("here we go " + Name + treeNum);
}
}
2) instantiating the ViewModel
var addDeviceMenuItem = new DeviceViewModel { Name = "AddDevice", treeNum = _itemId };
var addSensorMenuItem = new DeviceViewModel { Name = "AddSensor", treeNum = _itemId };
var addSpaceMenuItem = new DeviceViewModel { Name = "AddSpace", treeNum = _itemId };
var updateMenuItem = new DeviceViewModel { Name = "UpdateSpaceInfo", treeNum = _itemId };
var deleteMenuItem = new DeviceViewModel { Name = "DeleteSpace", treeNum = _itemId };
var items = new ObservableCollection<DeviceViewModel> { addDeviceMenuItem, addSensorMenuItem, addSpaceMenuItem, updateMenuItem, deleteMenuItem };
tree.Add(
new TreeItemModel
{
Branch = b,
Depth = d,
Text = "Item " + _itemId++,
Children = BuildTree(d, b),
MenuItems = items
});
with
ObservableCollection<DeviceViewModel> _menuItems;
public ObservableCollection<DeviceViewModel> MenuItems
{
get { return _menuItems; }
set { this.SetProperty(ref _menuItems, value); }
}
3) and finally binding the XAML to the ViewModel
<controls:TreeView x:Name="TreeViewList" Grid.Row="0" Margin="5" ItemsSource="{Binding TreeItems}">
<controls:TreeView.ItemTemplate>
<DataTemplate>
<data:DataTemplateExtensions.Hierarchy>
<data:HierarchicalDataTemplate ItemsSource="{Binding Children}"/>
</data:DataTemplateExtensions.Hierarchy>
<Button
x:Name="TreeButton" Content="{Binding Text}" BorderThickness="3" Background="Transparent">
<Button.Flyout>
<Flyout common:BindableFlyout.ItemsSource="{Binding MenuItems}">
<common:BindableFlyout.ItemTemplate>
<DataTemplate>
<MenuFlyoutItem Text="{Binding Name}" Command="{Binding FlyoutCommand}"/>
</DataTemplate>
</common:BindableFlyout.ItemTemplate>
</Flyout>
</Button.Flyout>
</Button>
</DataTemplate>
</controls:TreeView.ItemTemplate>
</controls:TreeView>
You can add the Command in the same code where you create the MenuFlyoutItem, so
var addDeviceMenuItem = new MenuFlyoutItem { Name = "AddDevice", Text = "Add Device"
};
addDeviceMenuItem.Command = AddDeviceCommand;