前文介绍了自定义或系统自带的ValidationRule进行验证,这种方法对于单个元素的验证不错。很多时候,我们需要对表单(Form)进行验证,也就是对一个实体类进行验证,或者对一个集合的每项进行验证,则显得不尽人意(每次只能验证一次)。WPF3.5中提供了BindingGroup用来验证多个绑定元素,可以对表单(form)和实体类进行验证。另外BindingGroup提供了Transcational的支持,就是说可以让操作回滚(BeginEdit,CancelEdit,CommitEdit)。BindingGroup的验证是同时进行的。可以设置BindingGroupName把一个Binding加入已存在的BindingGroup(就是BindingGroupName指定的)。

MSDN上是这样说的:

BindingGroup 在多个绑定之间创建关系,从而可一起验证和更新这些绑定。例如,假定某应用程序提示用户输入地址。然后该应用程序使用用户提供的值填充 Address 类型的对象,该对象具有 Street、City、ZipCode 和 Country 属性。该应用程序有一个包含四个 TextBox 控件的面板,其中每个控件均数据绑定到对象的属性之一。可以使用 BindingGroup 中的 ValidationRule 验证 Address 对象。如果绑定加入相同的 BindingGroup,则可以确保邮政编码对于地址所在国家/地区有效。

设置 FrameworkElement 或 FrameworkContentElement 上的 BindingGroup 属性。正如任何其他可继承属性一样,子元素从其父元素继承 BindingGroup。如果发生以下情况之一,则会将子代元素上的绑定添加到 BindingGroup:

在地址示例中,假定将 Panel 的 DataContext 设置为 Address 类型的对象。每个 TextBox 的绑定均添加到面板的 BindingGroup 中。

将 ValidationRule 对象添加到 BindingGroup 中。在运行 ValidationRule 时,将 BindingGroup 作为 Validate 方法的第一个参数传递。可以使用该 BindingGroup 上的 TryGetValue 或 GetValue(Object, String) 方法获取对象的建议值,使用 Items 属性获取绑定的源。

BindingGroup 在同一时间更新绑定的源,而不是分别更新每个绑定。在调用任一方法(ValidateWithoutUpdateUpdateSources 或 CommitEdit)验证数据时,将验证并可能会更新示例中的每个 TextBox 的绑定。当绑定是 BindingGroup 的一部分时,除非显式设置 UpdateSourceTrigger 属性,否则在对 BindingGroup 调用 UpdateSources 或 CommitEdit 之前,不会更新绑定的源。

BindGroup常用成员:

public class BindingGroup : DependencyObject
{
public Collection<BindingExpressionBase> BindingExpressions { get; }
public bool CanRestoreValues { get; }
public IList Items { get; }
public string Name { get; set; }
public bool NotifyOnValidationError { get; set; }
public Collection<ValidationRule> ValidationRules { get; } public void BeginEdit();
public void CancelEdit();
public bool CommitEdit();
public object GetValue(object item, string propertyName);
public bool TryGetValue(object item, string propertyName, out object value);
public bool UpdateSources();
public bool ValidateWithoutUpdate();
}
 
Items:BindingGroup 中的绑定对象所使用的源,是个List。所有作为源的对象都会被包含在Items中。通常,Items 中只有一项,即作为使用 BindingGroup 的元素的 DataContext 的对象。
但是,BindingGroup 也可以包含多个源。例如,如果绑定对象共享同一 BindingGroupName 但使用不同的源对象,则用作源的每个对象均在 Items 中。
如果绑定路径可解析为源的嵌套属性,则 Items 中也可有多个对象。例如,假定 TextBox 控件的绑定是 BindingGroup 的一部分,并且其 DataContext 是 Customer 对象,该对象具有 Address 类型的属性。
如果 BindingPath 为 Address.ZipCode 属性,则 Address 会添加到 Items 属性中。
 
NotifyOnValidationError:获取或设置在 ValidationRule 的状态更改时是否发生 Validation.Error 事件。
 
BeginEdit:开始编辑事务。
 
CommitEdit:运行所有的Rule,如果成功,则保存更改,更新源。
 
CancelEdit:取消更改。
 
以上三个,如果源对应的类继承自IEditableObject, 会调用IEditableObject中的相应方法。
 
UpdateSources:运行所有ValidationStep设置为RawProposedValueConvertedProposedValueUpdatedValue的Rule。如果成功,更新源。此方法不会挂起事务并结束事务,也就是说调用完该方法后事务还是处于运行中。
 
ValidateWithoutUpdate:如同UpdateSources,但是不会更新源。
 
所以有三个方法可以用作验证:CommitEdit,UpdateSources,ValidateWithoutUpdate。  

先看看验证实体类的示例:

<Window x:Class="ValidateItemSample.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:src="clr-namespace:ValidateItemSample"
Title="Validating an Object" Width="400" Height="500" ResizeMode="NoResize"> <StackPanel Name="stackPanel1" Margin="10"
Loaded="stackPanel1_Loaded"
Validation.Error="ItemError"><!--验证的错误在ItemError中处理,要求NotifyOnValidationError="True"--> <StackPanel.Resources>
<Style TargetType="HeaderedContentControl">
<Setter Property="Margin" Value="2"/>
<Setter Property="Focusable" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="HeaderedContentControl">
<DockPanel LastChildFill="False">
<ContentPresenter ContentSource="Header" DockPanel.Dock="Left" Focusable="False" VerticalAlignment="Center"/>
<ContentPresenter ContentSource="Content" Margin="5,0,0,0" DockPanel.Dock="Right" VerticalAlignment="Center"/>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style> <Style TargetType="Button">
<Setter Property="Width" Value="100"/>
<Setter Property="Margin" Value="10,15,15,15"/>
</Style>
</StackPanel.Resources>
    <!--BindingGroup-->
<StackPanel.BindingGroup>
<BindingGroup NotifyOnValidationError="True">
<BindingGroup.ValidationRules>
<src:ValidateDateAndPrice ValidationStep="ConvertedProposedValue" />
</BindingGroup.ValidationRules>
</BindingGroup>
</StackPanel.BindingGroup>
<TextBlock FontSize="12" TextWrapping="Wrap" Margin="5">
This sample demonstrates how to validate an object by checking
multiple properties in a ValidationRule. When a ValidationRule
is added to a BindingGroup, the rule can get the properties of
the source item in the Validate method.
<LineBreak/><LineBreak/>
This sample checks that if an item costs more than 100 dollars,
the item is available for at least 7 days.
</TextBlock> <TextBlock FontSize="14" FontWeight="Bold"
Text="Enter an item for sale"/> <HeaderedContentControl Header="Description">
<TextBox Width="150" Text="{Binding Path=Description, Mode=TwoWay}"/>
</HeaderedContentControl>
<HeaderedContentControl Header="Price">
<TextBox Name="priceField" Width="150">
<TextBox.Text>
<Binding Path="Price" Mode="TwoWay" >
            <!--自定义的ValidationRule-->
<Binding.ValidationRules>
<src:PriceIsAPositiveNumber/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
</HeaderedContentControl>
<HeaderedContentControl Header="Date Offer Ends">
<TextBox Name="dateField" Width="150" >
<TextBox.Text>
<Binding Path="OfferExpires" StringFormat="d" >
            <!--自定义的ValidationRule-->
<Binding.ValidationRules>
<src:FutureDateRule/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
</HeaderedContentControl>
<StackPanel Orientation="Horizontal">
<Button IsDefault="True" Click="Submit_Click">_Submit</Button>
<Button IsCancel="True" Click="Cancel_Click">_Cancel</Button>
</StackPanel>
<HeaderedContentControl Header="Description">
<TextBlock Width="150" Text="{Binding Path=Description}"/>
</HeaderedContentControl>
<HeaderedContentControl Header="Price">
<TextBlock Width="150" Text="{Binding Path=Price, StringFormat=c}"/>
</HeaderedContentControl>
<HeaderedContentControl Header="Date Offer Ends">
<TextBlock Width="150" Text="{Binding Path=OfferExpires, StringFormat=d}"/>
</HeaderedContentControl>
</StackPanel>
</Window>
 
        void stackPanel1_Loaded(object sender, RoutedEventArgs e)
{
// Set the DataContext to a PurchaseItem object.
// The BindingGroup and Binding objects use this as
// the source.
stackPanel1.DataContext = new PurchaseItem(); // Begin an edit transaction that enables
// the object to accept or roll back changes.
stackPanel1.BindingGroup.BeginEdit();
} private void Submit_Click(object sender, RoutedEventArgs e)
{
//验证并提交
            if (stackPanel1.BindingGroup.CommitEdit())
{
MessageBox.Show("Item submitted");
//提交成功后继续接收edit信息
                stackPanel1.BindingGroup.BeginEdit();
}
} private void Cancel_Click(object sender, RoutedEventArgs e)
{
// Cancel the pending changes and begin a new edit transaction.
stackPanel1.BindingGroup.CancelEdit();
stackPanel1.BindingGroup.BeginEdit();

} // This event occurs when a ValidationRule in the BindingGroup
// or in a Binding fails.
private void ItemError(object sender, ValidationErrorEventArgs e)
{
if (e.Action == ValidationErrorEventAction.Added)//描述是添加还是清除了 ValidationError 对象
{
MessageBox.Show(e.Error.ErrorContent.ToString());
}
}

ValidationRule文件:

    public class ValidateDateAndPrice : ValidationRule
{
// Ensure that an item over $100 is available for at least 7 days.
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
BindingGroup bg = value as BindingGroup; // Get the source object.
PurchaseItem item = bg.Items[0] as PurchaseItem; object doubleValue;
object dateTimeValue; // Get the proposed values for Price and OfferExpires.
bool priceResult = bg.TryGetValue(item, "Price", out doubleValue);
bool dateResult = bg.TryGetValue(item, "OfferExpires", out dateTimeValue); if (!priceResult || !dateResult)
{
return new ValidationResult(false, "Properties not found");
} double price = (double)doubleValue;
DateTime offerExpires = (DateTime)dateTimeValue; // Check that an item over $100 is available for at least 7 days.
if (price > 100)
{
if (offerExpires < DateTime.Today + new TimeSpan(7, 0, 0, 0))
{
return new ValidationResult(false, "Items over $100 must be available for at least 7 days.");
}
} return ValidationResult.ValidResult;
}
} //Ensure that the price is positive.
public class PriceIsAPositiveNumber : ValidationRule
{
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
try
{
double price = Convert.ToDouble(value); if (price < 0)
{
return new ValidationResult(false, "Price must be positive.");
}
else
{
return ValidationResult.ValidResult;
}
}
catch (Exception)
{
// Exception thrown by Conversion - value is not a number.
return new ValidationResult(false, "Price must be a number.");
}
}
} // Ensure that the date is in the future.
class FutureDateRule : ValidationRule
{
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{ DateTime date;
try
{
date = DateTime.Parse(value.ToString());
}
catch (FormatException)
{
return new ValidationResult(false, "Value is not a valid date.");
}
if (DateTime.Now.Date > date)
{
return new ValidationResult(false, "Please enter a date in the future.");
}
else
{
return ValidationResult.ValidResult;
}
}
} // PurchaseItem implements INotifyPropertyChanged and IEditableObject
// to support edit transactions, which enable users to cancel pending changes.
public class PurchaseItem : INotifyPropertyChanged, IEditableObject
{
struct ItemData
{
internal string Description;
internal double Price;
internal DateTime OfferExpires; static internal ItemData NewItem()
{
ItemData data = new ItemData();
data.Description = "New item";
data.Price = 0;
data.OfferExpires = DateTime.Now + new TimeSpan(7, 0, 0, 0); return data;
}
}
ItemData copyData = ItemData.NewItem();
ItemData currentData = ItemData.NewItem(); public PurchaseItem()
{ } public PurchaseItem(string desc, double price, DateTime endDate)
{
Description = desc;
Price = price;
OfferExpires = endDate;
} public override string ToString()
{
return String.Format("{0}, {1:c}, {2:D}", Description, Price, OfferExpires);
} public string Description
{
get { return currentData.Description; }
set
{
if (currentData.Description != value)
{
currentData.Description = value;
NotifyPropertyChanged("Description");
}
}
} public double Price
{
get { return currentData.Price; }
set
{
if (currentData.Price != value)
{
currentData.Price = value;
NotifyPropertyChanged("Price");
}
}
} public DateTime OfferExpires
{
get { return currentData.OfferExpires; }
set
{
if (value != currentData.OfferExpires)
{
currentData.OfferExpires = value;
NotifyPropertyChanged("OfferExpires");
}
}
} #region INotifyPropertyChanged Members public event PropertyChangedEventHandler PropertyChanged; private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
#endregion #region IEditableObject Members
public void BeginEdit()
{
copyData = currentData;
} public void CancelEdit()
{
currentData = copyData;
NotifyPropertyChanged(""); } public void EndEdit()
{
copyData = ItemData.NewItem(); }
#endregion
}
此例中PurchaseItem继承了IEditableObject,那么BindingGroup使用的BeginEdit,CancelEdit, EndEdit会使用IEditableObject中的相应方法。
 

对集合的验证:

下例点击Add Customer时,验证通过后会在集合中增加一个Customer对象,要求Customer所在区域与客服代表所在区域一致。
 
 
<Window x:Class="ValidateItemInItemsControlSample.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:src="clr-namespace:ValidateItemInItemsControlSample"
xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
Title="Window1">
<StackPanel>
<StackPanel.Resources>
<!--枚举值做数据源,使用ObjectDataProvider,这里有介绍-->
      <!--方法原型是Enum.GetValues(Type),返回值是一数组-->
<ObjectDataProvider MethodName="GetValues"
ObjectType="{x:Type sys:Enum}"
x:Key="RegionValues">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="src:Region" />
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
      <!—Representantives是ServiceRep(客服代表)实例的集合-->
<src:Representantives x:Key="SaleReps"/> <!—集合中各项的模版-->
      <DataTemplate x:Key="ItemTemplate" >
<StackPanel Orientation="Horizontal" >
<TextBlock Text="Customer Name" Margin="5"/>
<TextBox Width="100" Margin="5" Text="{Binding Name}"/>
<TextBlock Text="Region" Margin="5"/>
<ComboBox ItemsSource="{Binding Source={StaticResource RegionValues}}"
SelectedItem="{Binding Location}" Width="100" Margin="5"/>
<TextBlock Text="Service Representative" Margin="5"/>
<ComboBox ItemsSource="{Binding Source={StaticResource SaleReps}}"
SelectedItem="{Binding ServiceRepresentative}" Width="200" Margin="5"/>
<Button Content="Save Customer" Click="saveCustomer_Click"/>
</StackPanel>
</DataTemplate>
</StackPanel.Resources> <TextBlock FontSize="14" TextWrapping="Wrap" Margin="5">
This sample demonstrates how to validate an object in an ItemsControl.
The ValidationRule assigned to ItemsControl.ItemBindingGroup checks
multiple properties in the item.
This sample checks that a customer is assigned to a sales representative that serves their area.
</TextBlock> <!—设置Itemtemplate和ItemSource--> //注意ItemsControl的使用,在界面上的显示效果
    <ItemsControl Margin="5"  Name="customerList"  ItemTemplate="{StaticResource ItemTemplate}"
ItemsSource="{Binding}">
<ItemsControl.ItemBindingGroup>
<BindingGroup>
<BindingGroup.ValidationRules>
<src:AreasMatch/>
</BindingGroup.ValidationRules>
</BindingGroup>
</ItemsControl.ItemBindingGroup>

<!—获取或设置 Style,它应用于为每个项生成的容器元素。这是一个依赖项属性-->
      <ItemsControl.ItemContainerStyle>
        <!—ItemsControl里的每项实际是以ContentPresenter作为UI显示的载体-->
<Style TargetType="{x:Type ContentPresenter}">
<Setter Property="Validation.ValidationAdornerSite"
Value="{Binding ElementName=validationErrorReport}"/>

</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
<Label Name="validationErrorReport"
Content=
"{Binding RelativeSource={RelativeSource Self},
Path=(Validation.ValidationAdornerSiteFor).(Validation.Errors)[0].ErrorContent}"
Margin="5" Foreground="Red" HorizontalAlignment="Center"/>
<Button Content="Add Customer" Click="AddCustomer_Click" HorizontalAlignment="Center"/>
</StackPanel>
</Window>
这里用了一个Label(validationErrorReport)来显示验证错误信息,验证的错误是以Validation.Errors这个Attached Property作为载体。

通过Validation.ValidationAdornerSite和Validation.ValidationAdornerSiteFor可以设置错误消息源(ItemsControl中的各项)和接收错误的载体(Label)。
但是这种做法是有点问题的,我在另一篇中会讲这个例子的运行效果。其有问题的原因是因为Validation类是静态类,里面的所有成员及方法都是静态的,只能对一个有效。

Backend code:

    public partial class Window1 : Window
{
Customers customerData;
BindingGroup bindingGroupInError = null; public Window1()
{
InitializeComponent(); customerData = new Customers();
            // 设置ItemsControl的源
customerList.DataContext = customerData;
} void AddCustomer_Click(object sender, RoutedEventArgs e)
{
if (bindingGroupInError == null)
{
customerData.Add(new Customer());
}
else
{
MessageBox.Show("Please correct the data in error before adding a new customer.");
}
} void saveCustomer_Click(object sender, RoutedEventArgs e)
{
Button btn = sender as Button;
            // ItemsControl.ContainerFromElement MSND上是这么说的:返回属于拥有给定元素的当前 ItemsControl 的容器。读起来和念易筋经一样
FrameworkElement container = (FrameworkElement) customerList.ContainerFromElement(btn); // If the user is trying to change an items, when another item has an error,
// display a message and cancel the currently edited item.
if (bindingGroupInError != null && bindingGroupInError != container.BindingGroup)
{
MessageBox.Show("Please correct the data in error before changing another customer");
container.BindingGroup.CancelEdit();
return;
} if (container.BindingGroup.ValidateWithoutUpdate())
{
container.BindingGroup.UpdateSources();
bindingGroupInError = null;
MessageBox.Show("Item Saved");
}
else
{
bindingGroupInError = container.BindingGroup;
}
}
 
ValicationRule文件:
    public class Customers : ObservableCollection<Customer>
{
public Customers()
{
Add(new Customer());
}
} public enum Region
{
Africa,
Antartica,
Australia,
Asia,
Europe,
NorthAmerica,
SouthAmerica
} public class Customer
{
public string Name { get; set; }
public ServiceRep ServiceRepresentative { get; set; }
public Region Location { get; set; }
} public class ServiceRep
{
public string Name { get; set; }
public Region Area { get; set; } public ServiceRep()
{
} public ServiceRep(string name, Region area)
{
Name = name;
Area = area;
} public override string ToString()
{
return Name + " - " + Area.ToString();
}
} public class Representantives : ObservableCollection<ServiceRep>
{
public Representantives()
{
Add(new ServiceRep("Haluk Kocak", Region.Africa));
Add(new ServiceRep("Reed Koch", Region.Antartica));
Add(new ServiceRep("Christine Koch", Region.Asia));
Add(new ServiceRep("Alisa Lawyer", Region.Australia));
Add(new ServiceRep("Petr Lazecky", Region.Europe));
Add(new ServiceRep("Karina Leal", Region.NorthAmerica));
Add(new ServiceRep("Kelley LeBeau", Region.SouthAmerica));
Add(new ServiceRep("Yoichiro Okada", Region.Africa));
Add(new ServiceRep("T¨¹lin Oktay", Region.Antartica));
Add(new ServiceRep("Preeda Ola", Region.Asia));
Add(new ServiceRep("Carole Poland", Region.Australia));
Add(new ServiceRep("Idan Plonsky", Region.Europe));
Add(new ServiceRep("Josh Pollock", Region.NorthAmerica));
Add(new ServiceRep("Daphna Porath", Region.SouthAmerica));
}
} // Check whether the customer and service representative are in the
// same area.
public class AreasMatch : ValidationRule
{
public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
{
BindingGroup bg = value as BindingGroup;
Customer cust = bg.Items[0] as Customer;
if (cust == null)
{
return new ValidationResult(false, "Customer is not the source object");
} Region region = (Region)bg.GetValue(cust, "Location");
ServiceRep rep = bg.GetValue(cust, "ServiceRepresentative") as ServiceRep;
string customerName = bg.GetValue(cust, "Name") as string; // 相等说明验证通过
            if (region == rep.Area)
{
return ValidationResult.ValidResult;
}
else
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("{0} must be assigned a sales representative that serves the {1} region. \n ", customerName, region);
return new ValidationResult(false, sb.ToString());
}
}
} http://www.cnblogs.com/iwteih/archive/2012/04/10/2441576.html

WPF3.5 使用BINDINGGROUP进行实体类和集合验证的更多相关文章

  1. 关于entityframework 自动生成实体类中加验证的属性重新生成后属性被覆盖解决办法

    1.手动创建一个部分类 (你可以手动创建 partial class, 内容为空) [MetadataType(typeof(AppleMetadata))] public partial class ...

  2. 关于hibernate的实体类中有集合类型转化成JSON的工具类 - 怀念今天的专栏 - 博客频道

    Json 来源:http://blog.csdn.net/zczzsq/article/details/18697045#1536434-hi-1-4387-42d97150898b1af15ddaa ...

  3. Manual Validation with Data Annotations C#对实体类进行手动验证

    Several people have asked me about using data annotations for validation outside of a UI framework, ...

  4. oop典型应用:实体类

    1.什么是实体类 简单地说就是描述一个业务实体的“类”,业务实体直观一点理解就是整个就是整个软件系统业务所涉及的对象. eg:MySchool系统中的班级,学生,年级等都是业务实体,“雷电”游戏中的飞 ...

  5. Hibernate框架学习之注解映射实体类

         前面的相关文章中,我们已经介绍了使用XML配置文件映射实体类及其各种类型的属性的相关知识.然而不论是时代的潮流还是臃肿繁杂的配置代码告诉我们,注解配置才是更人性化的设计,于是学习了基本的映射 ...

  6. Do You Kown Asp.Net Core - 根据实体类自动创建Razor Page CURD页面模板

    Scaffolding Template Intro 我们知道在Asp.Net MVC中,如果你使用的EF的DBContext的话,你可以在vs中通过右键解决方案-添加控制器-添加包含视图的控制器,然 ...

  7. 使用FastJson对实体类和Json还有JSONObject之间的转换

    1. 实体类或集合转JSON串 String jsonString = JSONObject.toJSONString(实体类); 2.JSON串转JSONObject JSONObject json ...

  8. FastJson对实体类和Json还有JSONObject相互转换

    1. 实体类或集合转JSON串 String besnString = JSONObject.toJSONString(实体类); 2.JSON串转JSONObject JSONObject json ...

  9. .NET平台开源项目速览(18)C#平台JSON实体类生成器JSON C# Class Generator

    去年,我在一篇文章用原始方法解析复杂字符串,json一定要用JsonMapper么?中介绍了简单的JSON解析的问题,那种方法在当时的环境是非常方便的,因为不需要生成实体类,结构很容易解析.但随着业务 ...

随机推荐

  1. 博彩游戏(tyvj 1519)

    背景 Bob最近迷上了一个博彩游戏…… 描述 这个游戏的规则是这样的:每花一块钱可以得到一个随机数R,花上N块钱就可以得到一个随机序列:有M个序列,如果某个序列是产生的随机序列的子串,那么就中奖了,否 ...

  2. 【BZOJ4945&&UOJ317】游戏(2-sat,拓扑序)

    题意: 思路: 输出方案时有一个优秀的性质可以利用: tarjan缩点之后点所属的分量编号是原图的反的拓扑序 所以只需要在两种方案内找到所属分量编号较小的那个就行了,用来满足(i,i')那个限制 #i ...

  3. 机器人程序设计——之如何正确入门ROS | 硬创公开课(附视频/PPT)【转】

    转自:http://blog.exbot.net/archives/2966 导语:本期公开课面向想入手ROS却又不知从何下手的小伙伴,为大家梳理好学习思路. ROS和Android一样是开源的,功能 ...

  4. 通过jQuery Ajax提交表单数据时同时上传附件

    1.使用场景:需要使用ajax提交表单,但是提交的表单里含有附件上传 2.代码实现方式: <!-- HTML代码 --> <form method="post" ...

  5. 在 .Net Core xUnit test 项目中使用配置文件

    在对项目做集成测试的时候,经常会需要用到一些参数比如用户名密码等,这些参数不宜放在测试代码中.本文介绍一种方法:使用配置文件. 添加配置文件 在集成测试项目目录下新建文件:Configuration. ...

  6. [原创][SW]TortoiseSVN创建本地版本控制

    1. 简介 TortoiseSVN是一个Windows平台下的Subversion用户端软件,以Windows shell extension的方式写成.它是自由软件,以GNU通用公共许可证发布.(f ...

  7. 洛谷—— P2251 质量检测

    https://www.luogu.org/problemnew/show/P2251 题目背景 无 题目描述 为了检测生产流水线上总共N件产品的质量,我们首先给每一件产品打一个分数A表示其品质,然后 ...

  8. luogu P2056 采花

    题目描述 萧芸斓是 Z国的公主,平时的一大爱好是采花. 今天天气晴朗,阳光明媚,公主清晨便去了皇宫中新建的花园采花.花园足够大,容纳了 n 朵花,花有 c 种颜色(用整数 1-c 表示) ,且花是排成 ...

  9. Java创建和解析Json数据方法(二)——org.json包的使用

    (二)org.json包的使用 1.简介   工具包org.json.jar,是一个轻量级的,JAVA下的json构造和解析工具包,它还包含JSON与XML, HTTP headers, Cookie ...

  10. BT服务器的搭建(tracker-P2P服务器架设)(转)

    文章虽然有点老,但原理差不多. 继上一篇文章(http://www.cnblogs.com/EasonJim/p/6601146.html)介绍了BT的原理,现在来看下BT服务端搭建的原理. 一.BT ...