I haven't enough rep points to post an image yet but given a Silverlight 4 chart example using ColumnSeries, how can I make each of the sub columns within a single column that are currently stacked up on top of each other sit side by side?
e.g Column NVQ2 shows value columns for 5 different locations, Column NVQ3 shows value columns for 5 different locations
I need the locations to sit side by side and not be stacked on top of each other.
Code for the graph:
foreach (ER_Location theLocation in UserSelections.TheDataSet.ER_Locations)
{
ER_Year myYear = (ER_Year)SeriesSelection.SelectedItem;
ColumnSeries newSeries = new ColumnSeries();
newSeries.ItemsSource = UserSelections.GetDataRowsByYearAndLocation(theLocation.Location_ID, (int)myYear.Year);
newSeries.IndependentValueBinding = new System.Windows.Data.Binding("Variable_ID");
newSeries.DependentValueBinding = new System.Windows.Data.Binding("Value");
newSeries.Title = theLocation.Name;
newSeries.IsSelectionEnabled = true;
MainChart.Series.Add(newSeries);
}
Update:
This is how the chart is rendering at present:
My guess is your code has the following using statement:-
using System.Windows.Controls.DataVisualization.Charting.Compatible
There are actually two different types with the name ColumnSeries. One is in the above namespace and it derives from StackedColumnSeries.
However the original non-stacked ColumnSeries exists in the main Charting namespace. This type will place each column side-by-side. Hence I suspect all you need to do is eliminate the extra .Compatible from your using:-
using System.Windows.Controls.DataVisualization.Charting;
You will have to create a class with the color property.
Example,
public class MyColor
{
public Brush ChartColor { get; set; }
}
then create a list of your favorite colors like
List<MyColor> colorList = new List<MyColor>
{
new MyColor
{ ChartColor = new SolidColorBrush(Colors.Blue)},
new MyColor
{ ChartColor = new SolidColorBrush(Colors.Green) },
...
...
}
From Xaml, bind the background color of the datapoint to ChartColor
Related
I have seen several posts on various forms varying in times from 2006 to now about how to add hyperlinks to RichTextBox, but they all seem overly complex for what I want. I am creating a desktop chat client, and I receive input as strings, now among these strings may be some urls, I need those urls to be clickable. Which from what I gather means they need to be HyperLink objects.
Navigating through the RichTextBox and replacing the urls with HyperLinks seems to be no small feat. Does anyone have a relatively simple solution for this?
In my web client it's a simple one liner
value = value.replace(/(http:\/\/[^\s]+)/gi, '$1');
Never thought I'd see the day where C# actually makes it harder.
If you want to do an equivalent of value.replace(/(http:\/\/[^\s]+)/gi, '$1') in WPF:
<RichTextBox x:Name="MyRichTextBox" IsDocumentEnabled="True" IsReadOnly="True" />
And the code that converts the string is the following:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var htmlText = "Google's website is http://www.google.com";
MyRichTextBox.Document = ConvertToFlowDocument(htmlText);
}
private FlowDocument ConvertToFlowDocument(string text)
{
var flowDocument = new FlowDocument();
var regex = new Regex(#"(http:\/\/[^\s]+)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
var matches = regex.Matches(text).Cast<Match>().Select(m => m.Value).ToList();
var paragraph = new Paragraph();
flowDocument.Blocks.Add(paragraph);
foreach (var segment in regex.Split(text))
{
if (matches.Contains(segment))
{
var hyperlink = new Hyperlink(new Run(segment))
{
NavigateUri = new Uri(segment),
};
hyperlink.RequestNavigate += (sender, args) => Process.Start(segment);
paragraph.Inlines.Add(hyperlink);
}
else
{
paragraph.Inlines.Add(new Run(segment));
}
}
return flowDocument;
}
}
It uses the same regular expression you provided, which is lacking if you properly want to recognize URLs with a regular expression. This one doesn't recognize https ones and the last dot in the following sentence would be a part of the URL: "This is a URL: http://www.google.com/."
What the code does is to split the text based on the regular expression, iterate it and adds the correct elements to the FlowDocument constructed on the fly.
Clicking the Hyperlink should open your default browser.
Result:
That said, this is only good for read only usage of the RichTextBox (as indicated by the question in the comment).
I have a ListView inside of a Popup control (seems to be significant that it's in a Popup). The coded test is pretty basic, click a ToggleButton to open the popup, and then select an item in the ListView.
Except it seems that it can't find the item in the ListView.
System.ArgumentException: No row was specified as search container for
the control. To search for a cell control using 'ColumnIndex', you
must specify row as a container element or add 'RowIndex' to the
search property of the cell. Parameter name: SearchProperties Result
StackTrace: at
Microsoft.VisualStudio.TestTools.UITesting.ALUtility.ThrowDataGridRelatedException(String
errorString, String propertyName) at
Microsoft.VisualStudio.TestTools.UITesting.WpfControls.WpfCell.GetUITestControlsForSearch()
at
Microsoft.VisualStudio.TestTools.UITesting.UITestControl.get_QueryId()
at
Microsoft.VisualStudio.TestTools.UITesting.UITestControlSearchArgument.get_SingleQueryString()
at
Microsoft.VisualStudio.TestTools.UITesting.SearchHelper.GetUITestControlRecursive(Boolean
useCache, Boolean alwaysSearch, ISearchArgument searchArg, IList`1
windowTitles, Int32& timeLeft)
The generated code is failing at this point
uIItemCell.Checked = this.MyListBoxCellParams.UIItemCellChecked;
where uIItemCell comes from this property
public WpfCell UIItemCell
{
get
{
if ((this.mUIItemCell == null))
{
this.mUIItemCell = new WpfCell(this);
#region Search Criteria
this.mUIItemCell.SearchProperties[WpfCell.PropertyNames.ColumnHeader] = null;
this.mUIItemCell.SearchProperties[WpfCell.PropertyNames.ColumnIndex] = "1";
this.mUIItemCell.WindowTitles.Add("CodedUITestWindow");
#endregion
}
return this.mUIItemCell;
}
}
So I guess this is where the criteria should be specified, but what how? And should row be hard coded somehow? Why didn't the test editor set the row?
If it helps, this is the .ctor where UIItemCell (above) is specified, seems like more search params
public UIMyCellDataItem(UITestControl searchLimitContainer) :
base(searchLimitContainer)
{
#region Search Criteria
this.SearchProperties[UITestControl.PropertyNames.ControlType] = "DataItem";
this.SearchProperties["HelpText"] = "MyCell's helptext property, this is correctly specified, but the HelpText is used only as a tooltip";
this.WindowTitles.Add("CodedUITestWindow");
#endregion
}
Thanks
I've normally seen ListView treated as a List, and the items as ListItem. You might want to use inspect.exe or the UI Test Builder to look at the properties. You can try to manually code the control. Sorry for posting speculation as an answer. Too long to be a comment.
WpfWindow PopUpWindow = new WpfWindow();
PopUpWindow.SearchProperties[WpfWindow.PropertyNames.Name] = "Pop Up Window Name";
WpfList List = new WpfList(PopUpWindow);
List.SearchProperties[WpfList.PropertyNames.Name] = "List Name";
WpfListItem ItemToSelect = new WpfListItem(List);
ItemToSelect.SearchProperties[WpfListItem.PropertyNames.Name] = "List Item Name";
// Click button to activate pop up window
ItemToSelect.Select();
// Creating the controls.
WpfWindow mainWindow = new WpfWindow();
// Add search properties.
WpfTable table = new WpfTable(mainWindow);
// Add search properties
WpfRow row = new WpfRow(table);
// Add search properties.
WpfCell cell = new WpfCell(row);
// Add search properties.
// Just adding the table and row as containers.
row.Container = table;
cell.Container = row;
}
I create some RibbonButtons dynamically and add them to a group according to an xml file. The follwoing function is carried out as often as entries found in the xml file.
private void ExtAppsWalk(ExternalAppsXml p, AppsWalkEventArgs args)
{
RibbonButton rBtn = new RibbonButton();
rBtn.Name = args.Name;
Binding cmdBinding = new Binding("ExtAppCommand");
rBtn.SetBinding(RibbonButton.CommandProperty, cmdBinding);
Binding tagBinding = new Binding("UrlTag");
tagBinding.Mode = BindingMode.OneWayToSource;
rBtn.SetBinding(RibbonButton.TagProperty, tagBinding);
rBtn.Label = args.Haed;
rBtn.Tag = args.Url;
rBtn.Margin = new Thickness(15, 0, 0, 0);
MyHost.ribGrpExtern.Items.Add(rBtn);
}
I tried to use the Tag property to store the Url's to be started when the respective button is clicked. Unfortunately the binding to the Tag property gives me the last inserted Url only.
What would be the best way to figure out which button is hit or to update the Tag property.
The datacontext is by default the context of the Viewmodel. The RibbonGroup to which the Buttons are added is created in the xaml file at designtime. I use that construct:
MyHost.ribGrpExtern.Items.Add(rBtn);
to add the buttons. It maight not really be conform with the mvvm pattern. May be someone else has a better idea to carry that out.
I foud a solution for my problem here and use the RelayCommand class. So I can pass objects (my Url) to the CommandHandler.
RibbonButton rBtn = new RibbonButton();
rBtn.Name = args.Name;
Binding cmdBinding = new Binding("ExtAppCommand");
rBtn.SetBinding(RibbonButton.CommandProperty, cmdBinding);
rBtn.CommandParameter = (object)args.Url;
private void ExtAppFuncExecute(object parameter)
{
if (parameter.ToString().....//myUrl
I am working on a WPF app using the MVVM patterm, which I am learning. It uses EF4. I am trying to use a similar tabbed document interface style; several combo boxes on these tabs have the same items sources (from a sql db). Since this data almost never changes, it seemed like a good idea to make a repository object to get them when the app starts, and just reuse them for each viewmodel. For whatever reason though, even though I use new in the constructors, the lists are connected.
If I set a bound combo box on one tab, it gets set on another (or set when a new tab is created). I don't want this to happen, but I don't know why does.
The repository object is initialized before anything else, and just holds public lists. The views simply use items source binding onto the ObservableCollection. I am using the ViewModelBase class from the article. Here is the Viewmodel and model code.
ViewModel
TicketModel _ticket;
public TicketViewModel(TableRepository repository)
{
_ticket = new TicketModel(repository);
}
public ObservableCollection<Customer> CustomerList
{
get { return _ticket.CustomerList; }
set
{
if (value == _ticket.CustomerList)
return;
_ticket.CustomerList = value;
//base.OnPropertyChanged("CustomerList");
}
}
Model
public ObservableCollection<Customer> CustomerList { get; set; }
public TicketModel(TableRepository repository)
{
CustomerList = new ObservableCollection<Customer>(repository.Customers);
}
EDIT: I am sure this is the wrong way to do this, I am still working on it. Here is the new model code:
public TicketModel(TableRepository repository)
{
CustomerList = new ObservableCollection<Customer>((from x in repository.Customers
select
new Customer
{
CM_CUSTOMER_ID = x.CM_CUSTOMER_ID,
CM_FULL_NAME = x.CM_FULL_NAME,
CM_COMPANY_ID = x.CM_COMPANY_ID
}).ToList());
}
This causes a new problem. Whenever you change tabs, the selection on the combo box is cleared.
MORE EDITS: This question I ran into when uses Rachels answer indicates that a static repository is bad practice because it leaves the DB connection open for the life of the program. I confirmed a connection remains open, but it looks like one remains open for non-static classes too. Here is the repository code:
using (BT8_Entity db = new BT8_Entity())
{
_companies = (from x in db.Companies where x.CO_INACTIVE == 0 select x).ToList();
_customers = (from x in db.Customers where x.CM_INACTIVE == 0 orderby x.CM_FULL_NAME select x).ToList();
_locations = (from x in db.Locations where x.LC_INACTIVE == 0 select x).ToList();
_departments = (from x in db.Departments where x.DP_INACTIVE == 0 select x).ToList();
_users = (from x in db.Users where x.US_INACTIVE == 0 select x).ToList();
}
_companies.Add(new Company { CO_COMPANY_ID = 0, CO_COMPANY_NAME = "" });
_companies.OrderBy(x => x.CO_COMPANY_NAME);
_departments.Add(new Department { DP_DEPARTMENT_ID = 0, DP_DEPARTMENT_NAME = "" });
_locations.Add(new Location { LC_LOCATION_ID = 0, LC_LOCATION_NAME = "" });
However, now I am back to the ugly code above which does not seem a good solution to copying the collection, as the Customer object needs to be manually recreated property by property in any code that needs its. It seems like this should be a very common thing to do, re-using lists, I feel like it should have a solution.
Custom objects, such as Customer get passed around by reference, not value. So even though you're creating a new ObservableCollection, it is still filled with the Customer objects that exist in your Repository. To make a truly new collection you'll need to create a new copy of each Customer object for your collection.
If you are creating multiple copies of the CustomerList because you want to filter the collection depending on your needs, you can use a CollectionViewSource instead of an ObservableCollection. This allows you to return a filtered view of a collection instead of the full collection itself.
EDIT
If not, have you considered using a static list for your ComboBox items, and just storing the SelectedItem in your model?
For example,
<ComboBox ItemsSource="{Binding Source={x:Static local:Lists.CustomerList}}"
SelectedItem="{Binding Customer}" />
This would fill the ComboBox with the ObservableCollection<Customer> CustomerList property that is found on the Static class Lists, and would bind the SelectedItem to the Model.Customer property
If the SelectedItem does not directly reference an item in the ComboBox's ItemsSource, you need to overwrite the Equals() of the item class to make the two values equal the same if their values are the same. Otherwise, it will compare the hash code of the two objects and decide that the two objects are not equal, even if the data they contain are the same. As an alternative, you can also bind SelectedValue and SelectedValuePath properties on the ComboBox instead of SelectedItem.
I have a DataGridView that is bound - via a binding source - to a list of entities:
VehicleRepository:
private IObjectSet<Vehicles> _objectSet;
public VehicleRepository(VPEntities context)
{
_context = context;
_objectSet = context.Vehicles;
}
List<Vehicle> IVehicleRepository.GetVehicles(Model model)
{
return _objectSet
.Where(e => e.ModelId == model.ModelId)
.ToList();
}
In my presenter
private List<Vehicle> _vehicles;
...
_vehicles = _vehicleRepository.GetVehicles(_model);
_screen.BindTo(_vehicles);
in my view
public void BindTo(List<Vehicle> vehicles)
{
_vehicles = vehicles;
if (_vehicles != null)
{
VehicleBindingSource.DataSource = _vehicles;
}
}
This works fine - my grid displays the data as it should. However, in the grid I am wanting to replace the ModelId column with a description field from the Model table. I've tried changing the binding for the column from ModelId to Model.ModelDescription but the column just appears blank.
I'm pretty sure that the data is being loaded, as I can see it when I debug, and when the same list is passed to a details screen I can successfully bind the related data to text fields and see the data.
Am I doing something obviously wrong?
It's a bit manual, but it 'works on my machine'.
Add a column to your DataGridView for the description field and then after you set your DataSource iterate through like so.
Dim row As Integer = 0
foreach (entity In (List<Entity>)MyBindingSource.DataSource)
{
string description = entity.Description;
MyDataGridView.Rows[row].Cells["MyDescriptionCell"].Value = description;
row ++;
}
You get a readonly view of your lookup. I make the new column readonly, but you could write something to handle the user changing the field if you wanted updates to run back to the server. Might be messy though.
The answer involves adding unbound read only columns and setting their value in the DataGridView's DataBindingComplete event
as described here
You can just add a column to your DataGridView, and in the DataPropertyName you must set the [entity].[Field name you need] in your case you could do: VehiclesType.Description
then you must add another binding source for the VehiclesTypes to the form, fill it using your context, and your good to go ;)