how to select treeviewitem in wpf - wpf

hi everyone! i am new in wpf so forgive me i want more!!!
i am trying to build an application. i have a treeview that bounded a datasource. it is okay. i have two problems. First; how can i select an item from treeview? i wanna a new window popsup when i select an item; when i click another item; another window popsup. Second problem is that i can not change foreground and font.Thanks everyone in advance
namespace CellBiology
{
public partial class TreeView
{
public TreeView()
{
this.InitializeComponent();
BindTreeView();
}
public void BindTreeView()
{
OleDbConnection con = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=|DataDirectory|\\CellBiology.mdb;Persist Security Info=True");
try
{
con.Open();
OleDbCommand cmd = new OleDbCommand("Select * from Topics", con);
OleDbDataAdapter da = new OleDbDataAdapter(cmd);
DataSet ds = new DataSet();
da.Fill(ds, "Topics");
int row = ds.Tables["Topics"].Rows.Count;
List<MyMenuItem> myList = new List<MyMenuItem>();
if (row > 0)
{
for (int i = 0; i <= row - 1; i++)
{
myList.Add(new MyMenuItem(Convert.ToInt32(ds.Tables["Topics"].Rows[i][0].ToString()), ds.Tables["Topics"].Rows[i][1].ToString(), 0));
for (int j = 0; j <= row - 1; j++)
{
if (ds.Tables["Topics"].Rows[i][0].ToString() == ds.Tables["Topics"].Rows[j][2].ToString())
{
myList.Add(new MyMenuItem(Convert.ToInt32(ds.Tables["Topics"].Rows[j][0].ToString()), ds.Tables["Topics"].Rows[j][1].ToString(), Convert.ToInt32(ds.Tables["Topics"].Rows[i][0].ToString())));
for (int k = 0; k <= row - 1; k++)
{
if (ds.Tables["Topics"].Rows[j][0].ToString() == ds.Tables["Topics"].Rows[k][2].ToString())
{
myList.Add(new MyMenuItem(Convert.ToInt32(ds.Tables["Topics"].Rows[k][0].ToString()),
ds.Tables["Topics"].Rows[k][1].ToString(),
Convert.ToInt32(ds.Tables["Topics"].Rows[j][0].ToString())));
for (int l = 0; l <= row - 1; l++)
if (ds.Tables["Topics"].Rows[k][0].ToString() == ds.Tables["Topics"].Rows[l][2].ToString())
{
myList.Add(new MyMenuItem(Convert.ToInt32(ds.Tables["Topics"].Rows[l][0].ToString()),
ds.Tables["Topics"].Rows[l][1].ToString(), Convert.ToInt32(ds.Tables["Topics"].Rows[k][0].ToString())));
Dictionary<int, TreeViewItem> flattenedTree = new Dictionary<int, TreeViewItem>();
foreach (MyMenuItem item in myList)
{
TreeViewItem treenode = new TreeViewItem();
treenode.Header = item.TopicName;
treenode.Tag = item;
flattenedTree.Add(item.TopicID, treenode);
if (flattenedTree.ContainsKey(item.TopLevelID))
{
flattenedTree[item.TopLevelID].Items.Add(treenode);
}
else
{
myTreeView.Items.Add(treenode);
}
public class MyMenuItem
{
internal int TopicID { get; set; }
internal string TopicName { get; set; }
internal int TopLevelID { get; set; }
internal MyMenuItem(int topicid, string topicname, int toplevelid)
{
TopicID = topicid;
TopicName = topicname;
TopLevelID = toplevelid;
private void myTreeView_SelectedItemChanged(object sender, RoutedEventArgs e)
{
**how can i code here?**
}
}
}

To change the font:
myWindow.FontFamily = new FontFamily("Font Name");
Where the "Font Name" is the name of known font types, eg. "Times New Roman" or "Comic Sans MS". You can find more usages here.
To Change the foreground color:
myWindow.Foreground = new SolidColorBrush(Colors.Red);
Where Colors.Red is can be any 'pre-defined' color of your choice.
Hope it helps.

To answer your "how can i code here?" specifically, you can do the following to access the TreeViewItem:
TreeViewItem selectedTreeViewItem = ((TreeViewItem)e.NewValue);
Once you've got that you can access the data that that item represents via it's DataContext property like so:
MyDataType myData = (MyDataType)selectedTreeViewItem.DataContext;
To popup the new window you can create an instance of your Window sublass and either use ShowDialog, if you want it to be modal, or Show if you want to allow mulitple windows to be opened at the same time.

Related

How to duplicate a custom control (panel) programmatically

I am using C# in VS 2010. I created a custom panel and would like to add this custom panel 9 times so I created a loop to add a copy of the panel 9 times at equal distance from each other. Each panel will have its own text and image. All I'm getting though is a single panel. Any insight would be appreciated
public partial class Form1 : Form
{
int index = 0;
List<CutePanel.CustomPanel> MenuItems = new List<CutePanel.CustomPanel>();
public Form1()
{
InitializeComponent();
for (int i = 0; i < 9; i++)
{
this.cpTest.BackColor = System.Drawing.SystemColors.ActiveCaption;
this.cpTest.LabelText = "My super click text";
this.cpTest.Location = new System.Drawing.Point(12, 12+(64*i));
this.cpTest.Name = "cpTest";
this.cpTest.Size = new System.Drawing.Size(344, 58);
this.cpTest.SuperClick = null;
this.cpTest.TabIndex = 6;
}
cpTest.MouseClick += new MouseEventHandler(cpTest_MouseClick);
cpTest.SuperClick += new EventHandler(cpTest_SuperClick);
cpTest.LabelText = "This is my text.";
MenuItems.Add(cpTest);
}
void cpTest_SuperClick(object sender, EventArgs e)
{
tcTest.SelectedIndex = index++ % 2;
}
void cpTest_MouseClick(object sender, MouseEventArgs e)
{
tcTest.SelectedIndex = index++ % 2;
}
private void customPanel3_MouseClick(object sender, MouseEventArgs e)
{
tcTest.SelectedIndex = index++ % 2;
}
}
Thanks.
You have to make a distinction between your panel class and panel objects, also called instances of this class. Think of the class as a template that serves in creating objects. These objects are created with the new keyword:
for (int i = 0; i < 9; i++)
{
var cp = new CutePanel.CustomPanel();
cp.BackColor = System.Drawing.SystemColors.ActiveCaption;
cp.LabelText = "My super click text";
cp.Location = new System.Drawing.Point(12, 12+(64*i));
cp.Name = "cpTest" + i;
cp.Size = new System.Drawing.Size(344, 58);
cp.SuperClick = null;
cp.TabIndex = 6;
cp.MouseClick += new MouseEventHandler(cpTest_MouseClick);
cp.SuperClick += new EventHandler(cpTest_SuperClick);
cp.LabelText = "This is my text.";
MenuItems.Add(cp);
}
You can also assign it values from the existing panel:
cp.BackColor = cpTest.BackColor;
cp.Size = cpTest.Size;
...
An elegant way of making a duplicate is to include a Clone method in your panel class
public class CustomPanel
{
...
public CustomPanel Clone()
{
var cp = (CustomPanel)this.MemberwiseClone();
cp.Parent = null; // It has not yet been added to the form.
return cp;
}
}
Then
for (int i = 0; i < 9; i++)
{
CustomPanel cp = cpTest.Clone();
// Now only change the differing properties
cp.Location = new System.Drawing.Point(12, 12+(64*i));
cp.Name = "cpTest" + i;
cp.TabIndex += i + 1;
MenuItems.Add(cp);
}
but attention: If the cloned control is a container control containing other controls, you must clones those recursively as well. I.e., you must perform a deep clone! Creating new controls as shown in my first code snippet is safer.

unable to set Row.Readonly=false in Datagridview in winforms

I have a datagridview with its ReadOnly set true to prevent people editing.
then I have a button on each row. when I click on a specific button, I wrote:
private void DGGrade_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex > 0 && e.ColumnIndex == DGGrade.Columns["Edit"].Index)
{
DGGrade.Rows[DGGrade.CurrentCell.RowIndex].ReadOnly = false;
DGGrade.Rows[DGGrade.CurrentCell.RowIndex].DefaultCellStyle.BackColor = Color.White;
}
But it is not working. please help
I do not know the reason why it is not working but as far as i can tell from my test runs it has to deal how the data is bound. If you use dataGridView1.DataSource = GetDataSource(); then it did not work in my tests. I have read once about some of the drawbacks of automated binding but i could not find it. Here is the code that works. A row is only in EditMode after the User has clicked the button Edit in the corresponding row. I will be back later - let me know if you need more pointers.
public partial class Form1 : Form
{
int rowIndexOfEditableRow = -1;
public Form1() {
InitializeComponent();
CreateDataGridView(dataGridView1);
SetExistingDataGridViewRowsReadOnly();
this.dataGridView1.Columns.Add(GetBtnColumn());
}
private void SetExistingDataGridViewRowsReadOnly() {
DataGridViewRowCollection rows = this.dataGridView1.Rows;
foreach (DataGridViewRow row in rows) {
row.ReadOnly = true;
}
}
It seems that the grid must be filled manually - at least this way the change of ReadOnly works
public void CreateDataGridView(DataGridView dgv)
{
dgv.ColumnCount = 3;
dgv.Columns[0].Name = "Id";
dgv.Columns[1].Name = "Lastname";
dgv.Columns[2].Name = "City";
dgv.BackgroundColor = Color.Gray;
AddRowsToDataGridView(dgv);
}
private void AddRowsToDataGridView(DataGridView dgv)
{
string[] row1 = new string[]{"1", "Muller", "Seattle"};
string[] row2 = new string[]{"2", "Arkan", "Austin"};
string[] row3 = new string[]{"3", "Cooper", "New York"};
object[] rows = new object[] { row1, row2, row3 };
foreach (string[] rowArray in rows)
{
dgv.Rows.Add(rowArray);
}
}
Helper method to create a column with a button
public DataGridViewButtonColumn GetBtnColumn()
{
DataGridViewButtonColumn btnColumn = new DataGridViewButtonColumn();
btnColumn.HeaderText = "Edit";
btnColumn.Text = "Edit";
btnColumn.UseColumnTextForButtonValue = true;
return btnColumn;
}
Event handler checks if the user has clicked the edit button. In this case the current row will be set to ReadOnly = false. This allows that the user to edit the row. To emphasize it i changed the background color of the row.
private void DataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
int colIndex = e.ColumnIndex;
int rowIndex = e.RowIndex;
Type cellType = dataGridView1.Columns[colIndex].CellType;
if (cellType == typeof(DataGridViewButtonCell))
{
dataGridView1.Rows[rowIndex].ReadOnly = false;
dataGridView1.Rows[rowIndex].DefaultCellStyle.BackColor = Color.GreenYellow;
this.rowIndexOfEditableRow = rowIndex;
label1.Text = rowIndexOfEditableRow.ToString() + " " + colIndex.ToString();
}
}
If the Row-leave-Event is fired the style is reset and the global parameter which row is editable is set to the initial value
private void DataGridView1_RowLeave(object sender, DataGridViewCellEventArgs e)
{
int rowIndex = e.RowIndex;
dataGridView1.Rows[rowIndex].ReadOnly = true;
dataGridView1.Rows[rowIndex].DefaultCellStyle.BackColor = Color.White;
this.rowIndexOfEditableRow = -1;
}
}
The above code contains all (except the designer files) that you need to create this demo:

DataGrid CheckBox can't be checked

I got a problem with datagrid and DataGridCheckBoxClumn. First of all im creating struct for datagrid items:
public struct taxRateFromDatabase
{
public int rate { get; set; }
public string mark { get; set; }
public CheckBox c { get; set; }
}
And after that in my class adding columns, bindings etc:
StackPanel tSp = new StackPanel();
DataGrid taxRateDataGrid = new DataGrid();
DataGridTextColumn col0 = new DataGridTextColumn();
DataGridTextColumn col1 = new DataGridTextColumn();
DataGridCheckBoxColumn col2 = new DataGridCheckBoxColumn();
Binding b = new Binding("checkBox");
b.Mode = BindingMode.TwoWay;
b.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
taxRateDataGrid.Columns.Add(col0);
taxRateDataGrid.Columns.Add(col1);
taxRateDataGrid.Columns.Add(col2);
col0.Binding = new Binding("rate");
col1.Binding = new Binding("mark");
col2.Binding = b;
CheckBox c = new CheckBox();
c.Content = "a";
col0.Header = "Stawka";
col1.Header = "Oznaczenie";
col2.Header = "Status";
taxRateDataGrid.Items.Add(new taxRateFromDatabase { rate = 0, mark = "E", c = c });
taxRateDataGrid.Items.Add(new taxRateFromDatabase { rate = 1, mark = "G", c = c });
Problem is that I cant really check/uncheck that checkbox i have just added.
I have tried also without checkbox in struct definition (just empty datagridcheckboxcolumn), but that also doesnt work. Im creating it in class which will return datagrid so i cant really acces xaml.
Any sugestions will be appreciated ;)
I suggest you to use class instead struct (take a look here) and implement INotifyPropertyChanged interface in order to get the binding working.
Something like
public class TaxRateFromDatabase : INotifyPropertyChanged
{
private int _rate;
public int Rate
{
get { return _rate; }
set { _rate = value; OnPropertyChanged("Rate"); }
}
private string _mark;
public string Mark
{
get { return _mark; }
set { _mark = value; OnPropertyChanged("Mark"); }
}
private bool _isChecked;
public bool IsChecked
{
get { return _isChecked; }
set { _isChecked = value; OnPropertyChanged("IsChecked"); }
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
and for example
DataGrid taxRateDataGrid = new DataGrid();
DataGridTextColumn col0 = new DataGridTextColumn();
DataGridTextColumn col1 = new DataGridTextColumn();
DataGridCheckBoxColumn col2 = new DataGridCheckBoxColumn();
taxRateDataGrid.Columns.Add(col0);
taxRateDataGrid.Columns.Add(col1);
taxRateDataGrid.Columns.Add(col2);
col0.Binding = new Binding("Rate");
col1.Binding = new Binding("Mark");
col2.Binding = new Binding("IsChecked");
col0.Header = "Stawka";
col1.Header = "Oznaczenie";
col2.Header = "Status";
List<TaxRateFromDatabase> list = new List<TaxRateFromDatabase>();
list.Add(new TaxRateFromDatabase { Rate = 1, Mark = "E", IsChecked = true });
list.Add(new TaxRateFromDatabase { Rate = 23, Mark = "F", IsChecked = false });
taxRateDataGrid.ItemsSource = list;

Is a dashed border around a selected text/image element possible in Silverlight?

I have an image editor I'm developing in silverlight which has multiple text and image elements on one canvas, that are draggable etc. I need feedback for the user to highlight the selected element when it is clicked on by the user and highlight a different element instead if another is clicked. I think I should do this with a dashed border around the element, but I don't know if it's possible.
Below is my code relating to the elements -
Project.cs
namespace ImageEditor.Client.BLL
{
public class Project : INotifyPropertyChanged
{
private int numberOfElements;
#region Properties
private ObservableCollection<FrameworkElement> elements;
public ObservableCollection<FrameworkElement> Elements
{
get { return elements; }
set
{
elements = value;
NotifyPropertyChanged("Elements");
}
}
private FrameworkElement selectedElement;
public FrameworkElement SelectedElement
{
get { return selectedElement; }
set
{
selectedElement = value;
NotifyPropertyChanged("SelectedElement");
}
}
private TextBlock selectedTextElement;
public TextBlock SelectedTextElement
{
get { return selectedTextElement; }
set
{
selectedTextElement = value;
NotifyPropertyChanged("SelectedTextElement");
}
}
private Image selectedImageElement;
public Image SelectedImageElement
{
get { return selectedImageElement; }
set
{
selectedImageElement = value;
NotifyPropertyChanged("SelectedImageElement");
}
}
#endregion
#region Methods
private void AddTextElement(object param)
{
TextBlock textBlock = new TextBlock();
textBlock.Text = "New Text";
textBlock.Foreground = new SolidColorBrush(Colors.Gray);
textBlock.FontSize = 25;
textBlock.FontFamily = new FontFamily("Arial");
textBlock.Cursor = Cursors.Hand;
textBlock.Tag = null;
AddDraggingBehavior(textBlock);
textBlock.MouseLeftButtonUp += element_MouseLeftButtonUp;
this.Elements.Add(textBlock);
numberOfElements++;
this.SelectedElement = textBlock;
this.selectedTextElement = textBlock;
}
private BitmapImage GetImageFromLocalMachine(out bool? success, out string fileName)
{
OpenFileDialog dialog = new OpenFileDialog()
{
Filter = "Image Files (*.bmp;*.jpg;*.gif;*.png;)|*.bmp;*.jpg;*.gif;*.png;",
Multiselect = false
};
success = dialog.ShowDialog();
if (success == true)
{
fileName = dialog.File.Name;
FileStream stream = dialog.File.OpenRead();
byte[] data;
BitmapImage imageSource = new BitmapImage();
using (FileStream fileStream = stream)
{
imageSource.SetSource(fileStream);
data = new byte[fileStream.Length];
fileStream.Read(data, 0, data.Length);
fileStream.Flush();
fileStream.Close();
}
return imageSource;
}
else
{
fileName = string.Empty;
return new BitmapImage();
}
}
private void AddImageElement(object param)
{
bool? gotImage;
string fileName;
BitmapImage imageSource = GetImageFromLocalMachine(out gotImage, out fileName);
if (gotImage == true)
{
Image image = new Image();
image.Name = fileName;
image.Source = imageSource;
image.Height = imageSource.PixelHeight;
image.Width = imageSource.PixelWidth;
image.MaxHeight = imageSource.PixelHeight;
image.MaxWidth = imageSource.PixelWidth;
image.Cursor = Cursors.Hand;
image.Tag = null;
AddDraggingBehavior(image);
image.MouseLeftButtonUp += element_MouseLeftButtonUp;
this.Elements.Add(image);
numberOfElements++;
this.SelectedElement = image;
this.SelectedImageElement = image;
}
}
private void OrderElements()
{
var elList = (from element in this.Elements
orderby element.GetValue(Canvas.ZIndexProperty)
select element).ToList<FrameworkElement>();
for (int i = 0; i < elList.Count; i++)
{
FrameworkElement fe = elList[i];
fe.SetValue(Canvas.ZIndexProperty, i);
}
this.Elements = new ObservableCollection<FrameworkElement>(elList);
}
public void element_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
this.SelectedElement = sender as FrameworkElement;
if (sender is TextBlock)
{
this.SelectedTextElement = sender as TextBlock;
FadeOut(this.SelectedTextElement);
}
else if (sender is Image)
{
this.SelectedImageElement = sender as Image;
FadeOut(this.SelectedImageElement);
}
}
#endregion
More than needed there but you get a good idea of how it all works from that. How might I go about it? I'm still pretty new to silverlight
Edit:
This is my start attempt at a DashBorder Method, wherein I'm trying to make a rectangle the same dimensions as the selected element which will go around the element
public static void DashBorder(FrameworkElement element)
{
Rectangle rect = new Rectangle();
rect.Stroke = new SolidColorBrush(Colors.Black);
rect.Width=element.Width;
rect.Height=element.Height;
rect.StrokeDashArray = new DoubleCollection() { 2, 2 };
}
It appears to do nothing and isn't what I want to do anyway. Is there no way to make a dash border on a FrameworkElement directly?
I don't know how, but google does.
You can use the StrokeDashArray to achieve the desired effect,
example:
<Rectangle Canvas.Left="10" Canvas.Top="10" Width="100" Height="100"
Stroke="Black" StrokeDashArray="10, 2"/>
The first number in StrokeDashArray is the length of the dash, the
second number is the length of the gap. You can repeat the dash gap
pairs to generate different patterns.
Edit:
To do this in code create a rectangle and set it's StrokeDashArray property like this (code untested):
Rectangle rect = new Rectangle();
rect.StrokeThickness = 1;
double[] dashArray = new double[2];
dashArray[0] = 2;
dashArray[1] = 4;
rect.StrokeDashArray = dashArray;

Autocomplete with BackgroundWorker does not work

I'm using AutoCompleteBox from the wpf toolkit and I implement the populating by my own
since there is a lot of data and I want to do the search in a background thread.
this is what heppans when I search for the number 12.
while it should show me 4 results - 12,120,121,122.
What am I doing wrong ?
Guide on msdn that I tried to folow: http://msdn.microsoft.com/en-us/library/system.windows.controls.autocompletebox.populating(VS.95).aspx
XAML:
<Grid>
<Controls:AutoCompleteBox x:Name="txtSearch" Populating="AutoCompleteBox_Populating" Height="30" Background="Beige" />
</Grid>
Code behind:
public partial class Window1 : Window {
private int MAX_NUM_OF_RESULTS = 3;
public List<Person> Persons { get; set; }
public List<string> Results { get; set; }
public Window1() {
InitializeComponent();
Persons = new List<Person>();
for (var i = 0; i < 1000000; i++) {
Persons.Add(new Person { Name = i.ToString() });
}
Results = new List<string>();
}
private void AutoCompleteBox_Populating(object sender, PopulatingEventArgs e) {
e.Cancel = true;
var b = new BackgroundWorker();
b.RunWorkerAsync(txtSearch.SearchText);
b.DoWork += b_DoWork;
b.RunWorkerCompleted += b_RunWorkerCompleted;
}
void b_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
txtSearch.ItemsSource = Results;
txtSearch.PopulateComplete();
}
void b_DoWork(object sender, DoWorkEventArgs e) {
Results.Clear();
var counter = 0;
foreach (var person in Persons) {
if (person.Name.StartsWith(e.Argument.ToString())) {
Results.Add(person.Name);
counter++;
if (counter > MAX_NUM_OF_RESULTS) {
break;
}
}
}
}
}
Class Person:
public class Person {
public string Name;
}
Try change the order to the following
var b = new BackgroundWorker();
b.DoWork += b_DoWork;
b.RunWorkerCompleted += b_RunWorkerCompleted;
b.RunWorkerAsync(txtSearch.SearchText);
Are you certain your search logic is actually executing? If so, are the expected results in Results prior to assigning them to ItemsSource?
I think this:
var b = new BackgroundWorker();
b.RunWorkerAsync(txtSearch.SearchText);
b.DoWork += b_DoWork;
b.RunWorkerCompleted += b_RunWorkerCompleted;
Should be this:
var b = new BackgroundWorker();
b.DoWork += b_DoWork;
b.RunWorkerCompleted += b_RunWorkerCompleted;
b.RunWorkerAsync(txtSearch.SearchText);
Otherwise you risk having the worker start before setting up event handlers.

Resources